This section explains the tools, test frameworks, compilers and IDEs that have been used for testing of the software library. Some parts only explains which tools that have been used, and other give a wider description of how these tools can be used.
3.3.1
Unity
This unit test framework is written in the C language [7]. It is a small framework that only consists of a source file and two header files. The framework has features that are special for projects in the embedded space. Unity also includes helper tools. An example of a helper tools is the test runner generator, which generates all necessary code after the tests are written.
Unity has a lot of different assertions to create test for booleans, integer, floats, bitwise, integer ranges, strings, pointers and memory assertions. Integer variables can be tested at given bit-size, hex-values and of signed/unsigned type. Examples of some of these are given below:
TEST_ASSERT_TRUE Assert that a variable is true.
TEST_FAIL Will always return a test failure.
TEST_ASSERT_EQUAL_INT64 Compares two 64-bit signed integers.
TEST_ASSERT_INT_WITHIN Checks that an integer is in a given range.
TEST_ASSERT_BITS_HIGH Checks that the correct bitmask is set to high.
TEST_ASSERT_FLOAT_WITHIN Compares two floating values, with a given fault tolerance.
TEST_ASSERT_EQUAL_STRING Compare that two strings are equal.
TEST_ASSERT_EQUAL_PTR Checks that two pointers are the same.
TEST_ASSERT_EQUAL_MEMORY Checks two blocks of memory, to compare packed structs and buffers.
There are extensions to Unity, which make it possible to use test fixtures. Other assertions and options can be found in the Unity summary [8].
3.3.2
CMock
CMock is a software library used to generate mock modules from C header-files. CMock uses Ruby to generate mock modules from the function declarations that are specified in the header-files [3].
When CMock has generated mock modules, the next step will be to compile and link the mock modules instead of the real modules. Header-files are still used for declaration
of the methods. In the tests, the expectations of methods with parameters are set and return values set for non-void methods. The method under test is then called and the unit test is ready for compilation and testing.
When the tests has run it will give feedback if the function was called as many times as expected, if not it will return that it was called less or more times than expected. Return values will be injected when this is specified. All parameters will be asserted against the expectations that were set. It is also possible to configure CMock to verify that methods are called in the correct order.
Parsing
CMock is limited in parsing C. The way CMock do parsing is to use regular expression to parse the header-files. This limits the support to what it actually needs, but anyway it supports most of the necessary functionality. One point where CMock lacks support is parsing of custom data types, for examples structures, which becomes difficult to compare. Instead of parsing header-files with regular expressions, CMock could have used a C parser written in ruby, but currently there is none that supports most of C99 language. The developers have earlier announced that support for structure is on the way [9].
Mock types
CMock has five mock module types that can be generated. These are expect, array, callback, Cexception and ignore [4]. Expect is the basic function, that is used in most of the tests, it defines that the function shall be called, and all the parameters to the method are asserted. The array type takes an array as parameter, together with the size of the array and asserts all of these elements. The callback function will take a callback function as a parameter, and call this stub function when the mock is called. Cexception is a function that can be used together with Unity and CMock to create exceptions, Cexception is not used in this thesis. The last function is ignore, which ignore all calls to the mock function. An example of each of these functions is showed in Listing 3.1. 1 /* Expect */
void print_Expect(params);
3 void print_ExpectAndReturn(params, return_val); 5 /* Aray */
void print_ExpectWithArray(*ptr params, size);
7 void print_ExpectWithArrayAndReturn(*ptr params, size, return_val); 9 /* Callback */
void print_StubWithCallback(CMOCK_print_CALLBACK callback); 11
/* CException */
13 void print_ExpectAndThrow(params, throw_value); 15 /* Ignore */
void print_Ignore();
17 void print_IgnoreAndReturn(return_val);
Configuration
The configuration of CMock is done with YAML , where the configuration file is used as input to CMock. Some of the features that can be configured is that attributes can be ignored, configuration of which plugins to use for mock types, how types and custom types shall be threated and configuration of how strict the mock module should be with verifying call in the correct order. For a full overview of configurations is CMock, see the documentation [4].
Structures
The biggest problem with CMock is how it handles comparisons of structures. CMock do comparisons of structures, by comparing the memory byte by byte. This will result in problems when the structures are not packed. On embedded systems, structures will often be used as a memory register, and packing memory register can result in incorrect testing since packing a structure will result in a register that is different from on the embedded system. This can result in testing on a model that does not represent the actual model on the hardware. An unpacked structure will contain garbage values where data alignment/padding is necessary, which will make a test fail. There are some ways this can be solved:
• If it is possible to pack the structure, add -fpack-struct as an option to GCC, which will force that the structure is packed.
• Create a helper method for Unity that do the assertions, and add this to the con- figuration file for CMock.
• One possible way is to initialize the structure with calloc(size_t, size_t), which will initialize the memory block as zero.
• If it is not important to test the feature, ignore the mock module.
Inline functions
Inline functions are often used when programming in the C language, for functions that are often used. Since function call are expensive, inline functions can be used instead so the function are included in the code, instead of using a function call. static inline can be used to be make the definition private to one translation unit1.
In Energy Micro’s software library static inline is often used, which will make the code faster og by that use less energy. When generating mock modules with CMock this is a problem.
CMock ignores inline functions by default, because if a mock function of the function was created, it is not defined which of the functions that will be used by the compiler [10]. The way to solve this is to wrap the definition into a macro and define a function that will be used during test, as shown in Listing 3.2.
1A Translation unit is the output from preprocessing, that will be used by a compiler to create an
1 #ifdef TEST
void func_write(uint32_t *addr, uint32_t value); 3 #else
__STATIC_INLINE void func_write(uint32_t *addr, uint32_t value) 5 {
*((volatile uint32_t *)addr) = (uint32_t)value; 7 }
#endif
Listing 3.2: Redefinition of Inline Method when Using Mock Modules
3.3.3
Ceedling
Ceedling is an extension to RAKE [6], so it works as a build system for C projects. Ceedling is created to support test-driven development in C and is designed to connect Unity and CMock [2]. The functionality that Ceedling can support when running tests, is to list all test tasks, run all tests, run a specified module or run tests that depends on changes since last time the tests was run.
3.3.4
Compilers & IDEs
In addition to software used for testing there have been used several IDEs and compilers. GCC have been used for compiling and linking the tests that are run on the host computer. Compiling and upload in Windows was done with IAR, in Linux have CodeSourcery been used to compile the examples.
The ruby language has been used to create necessary script and to run the scripts that are used by Unity, Ceedling and CMock.