# Unit Testing with CMOCK setting up guide ## Introduction to Unit Testing with AFR Unit Testing with AFR uses the **cmake build** framework.
Code coverage is achieved with **gcov/lcov** and results are displayed in: *build/coverage/*
The executables are located in *build/bin*
The build is tested on Linux and Windows with WSL.
## Introduction to CMOCK **CMOCK** is a mocking framework, that automatically generates mocks. It gives the ability to set expectations and implement stubs/callbacks. This will allow you to call the functions to be tested and the **CMOCK** generated code will do all the rest for you.
For example suppose your module accesses the internet using sockets, but you want to test just your module (unit) without testing/calling any socket API function as this could be unpredictable, slow, hard to simulate all possible error scenarios and return codes.
In order to achieve that you tell **CMOCK** to mock the header file where the socket's APIs reside. For simplicity we will assume the only function used is *func*, **CMOCK** will generate the following mocks for you: ``` func_Ignore[AndReturn]([return_val]); func_ExpectAnyArgs[AndReturn]([return_val]); func_Expect[AndReturn](param1, param2,..., paramN ,[return_val]) func_StubWithCallback(function_callback) (*this is deprecated*) func_AddCallback func_Stub func_ExpectWithArray[AndReturn](param1, [depth1], param2, [depth2], ..., paramN, [depthN], [return_val]) func_ReturnThruPtr_[parameter name](ret_pointer) func_ReturnArrayThruPtr_parameeter(parameter, len) func_ReturnMemThruPtr_[parameter name](size, ret_memory) func_IgnoreArg_[parameter name]() ``` For a detailed explanation about these mocks check the official documentation:
The **CMOCK** official website click [here] (http://www.throwtheswitch.org/cmock)
The **CMOCK** git hub repository click [here] (https://github.com/ThrowTheSwitch/CMock)
## How to build and execute To build first go to the AFR root directory ``` $ cd afr_root $ cmake -B build -DAFR_ENABLE_UNIT_TESTS=on -DBOARD=linux -DVENDOR=pc -DCOMPILER=linux-gcc -DCMAKE_BUILD_TYPE=Debug $ cd build $ make $ make coverage ``` ## Setting up a new Unit Testing module in AFR To Setup a module for Unit Testing, as an example we will follow a walkthrough approach for **lwip_secure_sockets** which are located in *libraries/abstractions/secure_sockets*.
1. Open the file *tests/unit_test/linux/CMakeLists.txt* for editing.
Make sure at around line 15 the the Unit Test directory location exists in this case **../../../libraries** if not add it
``` cmake add_subdirectory(../../../libraries libraries) ``` This will make the build system include your files in the build process 2. Add an additional line in the CMakeLists.txt that is located in the directory mentioned above *libraries* ```cmake if (AFR_ENABLE_UNIT_TESTS) add_subdirectory(folder_name/project_name) return() endif() ``` 3. In the directory of the module to be tested create a new directory called *utest* 4. For simplicity, copy the CMakeLists.txt file from *libraries/abstractions/secure_sockets/utest/* into the new Unit Test Directory *utest* 5. Create a test soure file that ends with *_utest.c* it is where your test code will live
you will end up with 2 files in the utest directory (project_name_utest.c and CMakeLists.txt) 6. Edit the copied file (CMakeLists.txt) in the following way 1. Modify the *project_name* at the top to match the new one to be tested 2. Replace all headers in *mock_list* with the ones you the source file under test uses. ``` cmake list(APPEND mock_list "lwip/src/include/lwip/sockets.h" "my_file_to_mock.h" ) ``` 3. Replace all the include directories in *mock_include_list* with the directories your mocks are using ```cmake list(APPEND mock_include_list /my/file/dir/needs ) ``` 4. Replace the definitions in *mock_define_list* list with the definitions you see fit for your source files ``` cmake list(APPEND mock_define_list -DMY_DEFINE=1 ) ``` This will create header files in the following form: *mock_my_file.h* which you will have to include from your test code (project_name_utest.c) This compilation step would create a shared object with the name *project_name_mock.so* 5. Replace all the files in *real_source_files* with the source files you will be testing. This will create a library with the name *project_file_real.a* ``` cmake list(APPEND real_source_files code_to_test.c ) ``` 6. Replace all the directories in *real_include_directories* with the directories the source under test will include headers from ```cmake list(APPEND real_include_directories /my/under/test/source/needs ) ``` This compilation step would create an object library called *project_name_real.a* 7. Replace all directories in *test_include_directories* with what the test code needs (project_name_utest.c) ```cmake list(APPEND test_include_directories /my/test/code/needs ) ``` 8. And thats it for this file.. 9. At the end, this makefile will create the mocked header and source files, *project_name_mock.so*, *project_name_real.a*, and *project_name_utest* 7. Write your Unit Test code *project_name_utest.c* it is better if you copy a file from another place (for example, *secure_sockets*) to re-use its skeleton
A Few points to keep in mind: * There is no need to write a main function, it is automatically generated * Testing functions must start with *test_* * We use unity to test and assert results 8. You should be ready to go by now
Always remember, if it is not tested it doesn't work :( ... Happy Testing!