blob: e1c34a9e18bd7ad57812852ef6b079d775bab3bb [file] [log] [blame]
Imre Kisa21712e2019-10-08 12:56:59 +02001CppUTest
2========
3
4This document is based on CppUTest v3.8. CppUtest is a unit testing framework for testing C and C++ code. This document
5introduces the basic features of the framework. For further information check the `official manual of CppUTest`_.
6
7
8Why CppUTest?
9-------------
10
11First of all it was not our goal to develop a new unit testing framework while plenty of open source solutions are already
12available. There were no special requirements agains the unit testing framework that would rule out all existing frameworks so
13we only had to choose a suitable one for our current and possible future needs.
14
15We ended up selecting CppUTest because of its small footprint and easy portability. It also goes along with the standard xUnit
16frameworks' principles and provides a standard interface to the outside world. Some details are listed below.
17
18- C/C++ support
19- Small footprint (compared to Google Test)
20- Easy to use on embedded systems
21- Built-in mocking system (CppUMock)
22- Implements four-phase testing pattern (setup, exercise, verify, teardown)
23- Selective run of test cases
24- Standard output format (JUnit, TeamCity)
25
26
27Assertions
28----------
29
30Generally is a good practice to use more specific assertions because it can output more informative error messages in case of a
31failure. The generic form or assertions is ``assert(expected, actual)``. Each assert type has a _TEXT variant for user defined
32error messages as last parameter.
33
34- Boolean
35
36 - ``CHECK(condition)`` - Same as ``CHECK_TRUE``
37 - ``CHECK_TRUE(condition)``
38 - ``CHECK_FALSE(condition)``
39
40- C string
41
42 - ``STRCMP_EQUAL(expected, actual)``
43 - ``STRNCMP_EQUAL(expected, actual, length)``
44 - ``STRCMP_NOCASE_EQUAL(expected, actual)``
45 - ``STRCMP_CONTAINS(expected, actual)``
46 - ``STRCMP_NOCASE_CONTAINS(expected, actual)``
47
48- Integer
49
50 - ``LONGS_EQUAL(expected, actual)``
51 - ``UNSIGNED_LONGS_EQUAL(expected, actual)``
52 - ``LONGLONGS_EQUAL(expected, actual)``
53 - ``UNSIGNED_LONGLONGS_EQUAL(expected, actual)``
54 - ``BYTES_EQUAL(expected, actual)``
55 - ``SIGNED_BYTES_EQUAL(expected, actual)``
56 - ``POINTERS_EQUAL(expected, actual)``
57 - ``FUNCTIONPOINTERS_EQUAL(expected, actual)``
58
59- Enums
60
61 - ``ENUMS_EQUAL_INT(expected, actual)``
62 - ``ENUMS_EQUAL_TYPE(underlying_type, expected, actual)``
63
64- Other assertions
65
66 - ``CHECK_EQUAL(expected, actual)`` - Requires ``operator=`` and ``StringFrom(type)`` to be implemented
67 - ``CHECK_COMPARE(first, relop, second)`` - Same as ``CHECK_EQUAL`` but with any type of compare
68 - ``DOUBLES_EQUAL(expected, actual, threshold)``
69 - ``MEMCMP_EQUAL(expected, actual, size)``
70 - ``BITS_EQUAL(expected, actual, mask)``
71 - ``FAIL()`` or ``FAIL_TEST()`` - Test case fails if called
72 - ``CHECK_THROWS(expected, expression)`` - Catching C++ exceptions
73
74- Miscellaneous macros
75
76 - ``IGNORE_TEST`` - Same as ``TEST`` but it’s not called
77 - ``TEST_EXIT`` - Exists test
78 - ``UT_CRASH()`` - Crashes the test which is easy to catch with debugger
79 - ``UT_PRINT(text)`` - Generic print function
80
81
82Test runner
83-----------
84
85Test cases are collected automatically. Under the hood the ``TEST`` macros are creating global instances of classes and their
86constructor registers the test cases into the test registry. This happens before entering the ``main`` function. In the ``main``
87function only the ``RUN_ALL_TESTS`` macro needs to be placed with the command line arguments passed to it. On executing the
88binary the command line arguments will control the behaviour of the test process.
89
90.. code-block:: C++
91
92 #include "CppUTest/CommandLineTestRunner.h"
93
94 int main(int argc, char* argv[]) {
95 return RUN_ALL_TESTS(argc, argv);
96 }
97
98The default ``main`` implementation is added to all unit test suites by the
99build system.
100
101
102Command line options
103--------------------
104
105Command line options are available mainly for configuring the output format of
106the test binary and for filtering test groups or cases.
107
108- Output
109
110 - ``-v`` - Prints each test name before running them
111 - ``-c`` - Colorized output
112 - ``-o{normal, junit, teamcity}`` - Output format, junit can be processed by
113 most CIs
114 - ``-k packageName`` - Package name for junit output
115 - ``-lg`` - List test groups
116 - ``-ln`` - List test cases
117
118- Other
119
120 - ``-p`` - Runs each test case in separate processes
121 - ``-ri`` - Runs ignored test cases
122 - ``-r#`` - Repeats testing ``#`` times
123 - ``-s seed`` - Shuffles tests
124
125- Filtering test cases
126
127 - ``"TEST(groupName, testName)"`` - Running single test
128 - ``"IGNORE_TEST(groupName, testName)"`` -- Running single ignored test
129 - ``-g text`` - Runing groups containing text
130 - ``-n text`` - Runing tests containing text
131 - ``-sg text`` - Runing groups matching text
132 - ``-sn text`` - Runing tests matching text
133 - ``-xg text`` - Excluding groups containing text
134 - ``-xn text`` - Excluding tests containing text
135 - ``-xsg text`` - Excluding groups matching text
136 - ``-xsn text`` - Excluding tests matching text
137
138
139Troubleshooting
140---------------
141
142Output messages
143^^^^^^^^^^^^^^^
144
145When one of tests fails the first step is to run it separately and check its
146output message. Usually it shows the exact line of the file where the error
147happened.
148
149::
150
151 test_memcmp.cpp:17: error: Failure in TEST(memcmp, empty)
152 expected <1 0x1>
153 but was <0 0x0>
154
155The executed tests can be followed by adding ``-v`` command line option.
156
157::
158
159 ./memcmp -v
160 TEST(memcmp, different) - 0 ms
161 TEST(memcmp, same) - 0 ms
162 TEST(memcmp, empty) - 0 ms
163
164 OK (3 tests, 3 ran, 1 checks, 0 ignored, 0 filtered out, 0 ms)
165
166
167Catching failure with debugger
168^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
169
170If a failure happens in a helper function or in a loop where the assertion
171is called multiple times it is harder to get the exact environment of a failure.
172In this case it's a good practice to put a ``UT_CRASH()`` call into a
173conditional block which hits when the failure happens. This way the debugger can
174stop on failure because the code emits a signal.
175
176.. code-block:: C++
177
178 TEST(magic, iterate) {
179 int result;
180
181 for(int i = 0; i < 1000; i++) {
182 result = magic_function(i);
183
184 // Debug code
185 if (result) {
186 UT_CRASH();
187 }
188
189 LONGS_EQUAL(0, result);
190 }
191 }
192
193
194Using ``FAIL`` macro
195^^^^^^^^^^^^^^^^^^^^
196
197It's recommended to use ``FAIL`` macro in conditions that should never occur in
198tests. For example if a test case loads test data from an external file but the
199file could not be opened the ``FAIL`` macro should be used with an informative
200message.
201
202.. code-block:: C++
203
204 fd = open("test.bin", O_RDONLY);
205 if (fd < 0) {
206 FAIL("test.bin open failed");
207 }
208
209
210Interference between test cases
211^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
212
213Test cases can interfere if there's a global resource which was not restored to
214its original state after leaving a test case. This can be hard to find but at
215least the it's easy to make sure that this is root case of an error. Let's
216assume there's a global variable which is set during the test case but it
217original value is not restore at the end. CppUTest has an command line option
218for running each test case in separate process. This makes the global variable
219to have its original value at the beginning of the test cases. Basically if the
220test works by passing argument ``-p`` when running but fails without it, there's
221a good chance for having an interference between test cases.
222
223.. code-block:: C++
224
225 int x = 0;
226
227 TEST_GROUP(crosstalk) {
228 };
229
230 TEST(crosstalk, a) {
231 LONGS_EQUAL(0, x);
232 x = 1;
233 }
234
235 TEST(crosstalk, b) {
236 LONGS_EQUAL(0, x);
237 x = 1;
238 }
239
240 TEST(crosstalk, c) {
241 LONGS_EQUAL(0, x);
242 x = 1;
243 }
244
245By running the test executable with different command line arguments it produces
246a different result.
247
248.. code-block::
249
250 ./crosstalk -v
251
252 TEST(crosstalk, c) - 0 ms
253 TEST(crosstalk, b)
254 test_crosstalk.cpp:37: error:
255 Failure in TEST(crosstalk, b)
256 expected <0 0x0>
257 but was <1 0x1>
258
259 - 0 ms
260 TEST(crosstalk, a)
261 test_crosstalk.cpp:32: error: Failure in TEST(crosstalk, a)
262 expected <0 0x0>
263 but was <1 0x1>
264
265 - 0 ms
266
267 Errors (2 failures, 3 tests, 3 ran, 3 checks, 0 ignored, 0 filtered out, 0 ms)
268
269 ./crosstalk -v -p
270 TEST(crosstalk, c) - 1 ms
271 TEST(crosstalk, b) - 0 ms
272 TEST(crosstalk, a) - 0 ms
273
274 OK (3 tests, 0 ran, 0 checks, 0 ignored, 0 filtered out, 2 ms)
275
276
277--------------
278
279*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
280
281.. _`official manual of CppUTest`: https://cpputest.github.io/