1 # Test Framework |
1 # Test Framework |
|
2 |
|
3 UCX brings its own testing framework, which can also be used by your applications. |
|
4 |
|
5 A test new suite is created by `cx_test_suite_new()`. |
|
6 An arbitrary number of test cases can be registered with `cx_test_register()`. |
|
7 |
|
8 ```C |
|
9 CxTestSuite *suite = cx_test_suite_new("My Suite"); |
|
10 |
|
11 cx_test_register(suite, test_foo); |
|
12 cx_test_register(suite, test_bar); |
|
13 cx_test_register(suite, test_baz); |
|
14 ``` |
|
15 |
|
16 A test case needs to be defined with the `CX_TEST` macro. |
|
17 The general structure of a test case is 1) setup code, 2) the actual test, 3) tear down code. |
|
18 In UCX this is realized by the `CX_TEST_DO` macro with which you can define a scope for the actual test. |
|
19 Whenever a test assertion fails, the scope is exited and the tear down code is executed. |
|
20 |
|
21 <tabs> |
|
22 <tab title="Test"> |
|
23 <code-block lang="C"> |
|
24 CX_TEST(test_foo) { |
|
25 struct mystruct *x = malloc(sizeof(*x)); |
|
26 x->d = 42; |
|
27 CX_TEST_DO { |
|
28 int y = foo(x); |
|
29 |
|
30 // auto-generated failure message |
|
31 CX_TEST_ASSERT(y == 42); |
|
32 |
|
33 // alternatively: custom failure message |
|
34 CX_TEST_ASSERTM(y == 42, |
|
35 "foo does not return correct value"); |
|
36 } |
|
37 free(x); |
|
38 } |
|
39 </code-block> |
|
40 </tab> |
|
41 <tab title="Implementation"> |
|
42 <code-block lang="C"> |
|
43 struct mystruct { |
|
44 int d; |
|
45 }; |
|
46 |
|
47 int foo(struct mystruct *s) { |
|
48 return s->d; |
|
49 } |
|
50 </code-block> |
|
51 </tab> |
|
52 </tabs> |
|
53 |
|
54 Once you have registered all test cases, you can run the test suite with `cx_test_run()` |
|
55 or one of the convenience macros. |
|
56 |
|
57 <tabs> |
|
58 <tab title="stdout"> |
|
59 <code-block lang="C"> |
|
60 cx_test_run_stdout(suite); |
|
61 </code-block> |
|
62 </tab> |
|
63 <tab title="FILE*"> |
|
64 <code-block lang="C"> |
|
65 FILE *f = fopen("test-result.txt", "w"); |
|
66 cx_test_run_f(suite, f); |
|
67 fclose(f); |
|
68 </code-block> |
|
69 </tab> |
|
70 <tab title="Other"> |
|
71 <code-block lang="C"> |
|
72 // for example: UCX buffer |
|
73 CxBuffer buf; |
|
74 cxBufferInit(&buf, NULL, 1024, NULL, 0); |
|
75 cx_test_run(suite, &buf, cxBufferWriteFunc); |
|
76 // do something with the buffer |
|
77 cxBufferDestroy(&buf); |
|
78 </code-block> |
|
79 </tab> |
|
80 </tabs> |
|
81 Finally, clean up all resources consumed by the test suite. |
|
82 |
|
83 ```C |
|
84 cx_test_suite_free(suite); |
|
85 ``` |
|
86 |
|
87 ## Test Subroutines |
|
88 |
|
89 For parameterized testing you can define and call test subroutines. |
|
90 It is _not_ possible to call arbitrary functions and use the `CX_TEST_ASSERT` macro. |
|
91 Instead, you define a callable test subroutine with `CX_TEST_SUBROUTINE` and call it with `CX_TEST_CALL_SUBROUTINE`. |
|
92 The following example illustrates this with an adaption of the above test case. |
|
93 |
|
94 <code-block lang="C"> |
|
95 CX_TEST_SUBROUTINE(test_foo_params, struct mystruct *x, int d) { |
|
96 x->d = d; |
|
97 CX_TEST_ASSERT(foo(x) == d); |
|
98 } |
|
99 |
|
100 CX_TEST(test_foo) { |
|
101 struct mystruct *x = malloc(sizeof(*x)); |
|
102 CX_TEST_DO { |
|
103 CX_TEST_CALL_SUBROUTINE(test_foo_params, x, 42); |
|
104 CX_TEST_CALL_SUBROUTINE(test_foo_params, x, -42); |
|
105 CX_TEST_CALL_SUBROUTINE(test_foo_params, x, 1337); |
|
106 } |
|
107 free(x); |
|
108 } |
|
109 </code-block> |
|
110 |
|
111 > Any test function, test case or test subroutine, is a normal C function. |
|
112 > As such you can decide to make them `static` when you do not want external linkage. |
|
113 > For example, just define the test as `static CX_TEST(test_foo)` instead of `CX_TEST(test_foo)`. |
|
114 |
|
115 <seealso> |
|
116 <category ref="apidoc"> |
|
117 <a href="https://ucx.sourceforge.io/api/test_8h.html">test.h</a> |
|
118 </category> |
|
119 </seealso> |