-
Notifications
You must be signed in to change notification settings - Fork 19
unit test frameworks Integration
- Prerequisites
- Introduction
- How CMock and Unity Work
- Integrate CMock/Unity with project files
- Gcovr Integration
- Main makefile
This wiki page outlines the integration process of CMock, Unity, and gcovr.
First, we need to know that CMock and Unity are just some source and header files that should be compiled and linked with your test files.
flowchart TD;
A[componant object files *.o];
B[unity.o];
C[cmock.o];
D[Executable file];
E[_______ LINKER _______];
F[mock_*.o];
A --> E ;
B --> E ;
C --> E ;
E --> D ;
F --> E ;
But to generate the component mock files mock_*
, we need a built-in Ruby script located at CMock/lib/cmock.rb
(it is a ruby script).
flowchart TD;
E[a.h] --> C ;
F[b.h] --> C ;
H[*.h] --> C ;
A[CMock config file] --> B[_______CMock/lib/cmock.rb_______] ;
C[COMPONANT_NAME_mock_header_files] --> B ;
B --> I[mock_a.h & mock_a.c];
B --> J[mock_b.h & mock_b.c];
B --> K[mock_*.h & mock_*.c];
If CMock config file
is not provided, the script will use the default configuration.
Gcovr is available as a Python package that can be installed via pip
.
Either --coverage
or -fprofile-arcs -ftest-coverage
are needed so that the compiler produces the information necessary to gather coverage data.
The gcovr tool searches recursively from the root directory, looking for *.gcno
files to generate coverage reports.
Let us take the software/bsw/mcal/port_swc
as example
The working tree should be
software/bsw/mcal/port_swc
│
├── CMakeLists.txt
├── core
│ ├── Port.c
│ ├── Port.h
│ └── Port_MemMap.h
├── tests
│ └── unit
│ ├── test_port_swc.c
│ └── test_runners
│ ├── all_tests.c
│ └── port_Runner.c
└── tools
└── cmake
├── port_swc_compile.cmake
└── port_swc_tests.cmake
Start with tools/cmake/port_swc_tests.cmake
It will contain this variables:
-
port_swc_tests_sources_list
: This variable contains:- Main test source files:
test_port_swc
,test_runners/all_tests.c
, andtest_runners/port_Runner.c
. - All mock files located in
${MOCK_FILE_PATH}/mocks/mock_Det.c
must be included.
- Main test source files:
-
port_swc_ut_sources_list
: This variable contains:- The source code of the main component:
${port_swc}/core/Port.c
. - All dependencies of
Port.c
, such as${gendata}/Port_Lcfg.c
and${gendata}/Port_PBcfg.c
.
- The source code of the main component:
-
port_swc_mock_header_files
: This variable contains all files that need to be mocked, such asDet.h
and any dependencies. -
port_swc_tests_includes
: This variable includes all header files related to theport_swc
component. -
port_swc_tests_compile_options
: This variable contains any extra compiler options needed. -
port_swc_tests_defines
: This variable contains all macros that need to be defined during compilation for all source files.
and for software/bsw/mcal/port_swc/CMakeLists.txt
Snippet from CMake file:
extract_module_path(port_swc MOCK_FILE_PATH)
if(MODE STREQUAL "TESTING")
# Execute CMock script
execute_process(
COMMAND ruby ${CMOCK_SCRIPT} -o${CMOCK_CONFIG_FILE} ${port_swc_mock_header_files}
OUTPUT_VARIABLE CMOCK_OUTPUT
WORKING_DIRECTORY ${MOCK_FILE_PATH}
)
message("CMock output: ${CMOCK_OUTPUT}")
# Testing Mode: Build the library and test executable
include(tools/cmake/port_swc_tests.cmake)
add_executable(port_swc_test ${port_swc_tests_sources_list} ${unity_common_sources})
target_compile_definitions(port_swc_test PRIVATE ${port_swc_tests_defines})
target_compile_options(port_swc_test PRIVATE ${dio_swc_tests_compile_options})
target_include_directories(port_swc_test PRIVATE ${port_swc_tests_includes} ${unity_common_includes})
target_link_libraries(port_swc_test PRIVATE port_swc)
endif()
For extract_module_path(port_swc MOCK_FILE_PATH) function
it used to extract the path of port_swc
within the Build directory and then assigns it to the variable named MOCK_FILE_PATH
so we can use it in Start with tools/cmake/port_swc_tests.cmake
- For mock file generation we must excute the ruby script first
# Execute CMock script
execute_process(
COMMAND ruby ${CMOCK_SCRIPT} -o${CMOCK_CONFIG_FILE} ${port_swc_mock_header_files}
OUTPUT_VARIABLE CMOCK_OUTPUT
WORKING_DIRECTORY ${MOCK_FILE_PATH}
)
- The
CMOCK_SCRIPT
variable at tools/build/CMake/user.cmake - The
CMOCK_CONFIG_FILE
variable in tools/build/CMake/cmockConfig.yml
You can overwite the default config file by change the o${CMOCK_CONFIG_FILE}
with new configuration path
execute_process(
COMMAND ruby ${CMOCK_SCRIPT} -o./test/unit/myConfig.yml ${port_swc_mock_header_files}
OUTPUT_VARIABLE CMOCK_OUTPUT
WORKING_DIRECTORY ${MOCK_FILE_PATH}
)
-
port_swc_mock_header_files
This variable contains the list of header need to be mocked. -
CMOCK_OUTPUT
This variable contains the output of the Ruby script execution -
unity_common_sources
This variable contains all source files of unity/CMock frameworks (Must be included withinadd_executable
) -
unity_common_includes
This variable contains all header files of unity/CMock frameworks (Must be included withintarget_include_directories
)
Now, all components are compiled and linked together, and it will generate test executable file each componant. (Take a look at the main Makefile section)
- We must add
--coverage
compiler flag to gcc
in tools/build/CMake/test_toolchain.cmake
set(COMMON_FLAGS "-Og -g -Wall --coverage")
-
coverage
rule in Makefile
GCOVR_INCLUDE_PATHS := '.*/core/.*'
gcovr -r . --filter ${GCOVR_INCLUDE_PATHS} \
--html-self-contained \
--html-theme ${HTML_THEME} \
--html-nested \
--cobertura \
--html=$(UNIT_TESTS_INSTALL_DIR)/html/test_report.html \
--xml=$(UNIT_TESTS_INSTALL_DIR)/test_report.xml \
-j$(MAXIMUM_CPU_CORES);
-
r .
Recursively search from the root directory/workspace
in case of the devcontainer -
--filter ${GCOVR_INCLUDE_PATHS}
generates coverage only for paths matching the pattern**/core/.*c
(representing the main source files of the SWC). -
--html=$(UNIT_TESTS_INSTALL_DIR)/html/test_report.html
--xml=$(UNIT_TESTS_INSTALL_DIR)/test_report.xml \
Set output dir for html and xml reports. - you can set the theme of html reports by pass option
HTML_THEME
likemake coverage HTML_THEME=green
The unit_test
rule consist of 3 subrules:
-
build_test
: This rule generates the executable test files for each component included in CMake. -
test
: This rule will- runs each program in
$(TEST_DIRS)
that has/*_test
-it is indicating test executable files- . - generate test report file in
$(UNIT_TESTS_INSTALL_DIR)/test_results.txt
- echo the test output on the shell screen.
- runs each program in
-
coverage
: This rule will gnerate html and xml coverage report for each SWC. - Additionally,
unit_test
rule will echo the test summary using the built-in Ruby script parse_output.rb, usingtest_results.txt
as the input file.
flowchart TD;
A[test_results.txt]
B[--------- parse_output.rb ---------]
C[echo Test summary ]
A --> B --> C ;