-
Notifications
You must be signed in to change notification settings - Fork 211
/
check.texi
2329 lines (1927 loc) · 84.3 KB
/
check.texi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename check.info
@include version.texi
@settitle Check @value{VERSION}
@syncodeindex fn cp
@syncodeindex tp cp
@syncodeindex vr cp
@c %**end of header
@copying
This manual is for Check
(version @value{VERSION}, @value{UPDATED}),
a unit testing framework for C.
Copyright @copyright{} 2001--2014 Arien Malec, Branden Archer, Chris Pickett,
Fredrik Hugosson, and Robert Lemmen.
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the @acronym{GNU} Free Documentation License,
Version 1.2 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover texts, and no
Back-Cover Texts. A copy of the license is included in the section
entitled ``@acronym{GNU} Free Documentation License.''
@end quotation
@end copying
@dircategory Software development
@direntry
* Check: (check). A unit testing framework for C.
@end direntry
@titlepage
@title Check
@subtitle A Unit Testing Framework for C
@subtitle for version @value{VERSION}, @value{UPDATED}
@author Arien Malec
@author Branden Archer
@author Chris Pickett
@author Fredrik Hugosson
@author Robert Lemmen
@author Robert Collins
@c The following two commands start the copyright page.
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@c Output the table of contents at the beginning.
@contents
@ifnottex
@node Top, Introduction, (dir), (dir)
@top Check
@insertcopying
Please send corrections to this manual to
@email{check-devel AT lists.sourceforge.net}. We'd prefer it if you can
send a unified diff (@command{diff -u}) against the
@file{doc/check.texi} file that ships with Check, but if that is not
possible something is better than nothing.
@end ifnottex
@menu
* Introduction::
* Unit Testing in C::
* Tutorial::
* Advanced Features::
* Supported Build Systems::
* Conclusion and References::
* Environment Variable Reference::
* Copying This Manual::
* Index::
@detailmenu
--- The Detailed Node Listing ---
Unit Testing in C
* Other Frameworks for C::
Tutorial: Basic Unit Testing
* How to Write a Test::
* Setting Up the Money Build Using Autotools::
* Setting Up the Money Build Using CMake::
* Test a Little::
* Creating a Suite::
* SRunner Output::
Advanced Features
* Convenience Test Functions::
* Running Multiple Cases::
* No Fork Mode::
* Test Fixtures::
* Multiple Suites in one SRunner::
* Selective Running of Tests::
* Testing Signal Handling and Exit Values::
* Looping Tests::
* Test Timeouts::
* Determining Test Coverage::
* Finding Memory Leaks::
* Test Logging::
* Subunit Support::
Test Fixtures
* Test Fixture Examples::
* Checked vs Unchecked Fixtures::
Test Logging
* XML Logging::
* TAP Logging::
Environment Variable Reference
Copying This Manual
* GNU Free Documentation License:: License for copying this manual.
@end detailmenu
@end menu
@node Introduction, Unit Testing in C, Top, Top
@chapter Introduction
@cindex introduction
Check is a unit testing framework for C. It was inspired by similar
frameworks that currently exist for most programming languages; the
most famous example being @uref{http://www.junit.org, JUnit} for Java.
There is a list of unit test frameworks for multiple languages at
@uref{http://www.xprogramming.com/software.htm}. Unit testing has a
long history as part of formal quality assurance methodologies, but
has recently been associated with the lightweight methodology called
Extreme Programming. In that methodology, the characteristic practice
involves interspersing unit test writing with coding (``test a
little, code a little''). While the incremental unit test/code
approach is indispensable to Extreme Programming, it is also
applicable, and perhaps indispensable, outside of that methodology.
The incremental test/code approach provides three main benefits to the
developer:
@enumerate
@item
Because the unit tests use the interface to the unit being tested,
they allow the developer to think about how the interface should be
designed for usage early in the coding process.
@item
They help the developer think early about aberrant cases, and code
accordingly.
@item
By providing a documented level of correctness, they allow the
developer to refactor (see @uref{http://www.refactoring.com})
aggressively.
@end enumerate
That third reason is the one that turns people into unit testing
addicts. There is nothing so satisfying as doing a wholesale
replacement of an implementation, and having the unit tests reassure
you at each step of that change that all is well. It is like the
difference between exploring the wilderness with and without a good
map and compass: without the proper gear, you are more likely to
proceed cautiously and stick to the marked trails; with it, you can
take the most direct path to where you want to go.
Look at the Check homepage for the latest information on Check:
@uref{https://libcheck.github.io/check/}.
The Check project page is at:
@uref{https://github.com/libcheck/check}.
@node Unit Testing in C, Tutorial, Introduction, Top
@chapter Unit Testing in C
@ C unit testing
The approach to unit testing frameworks used for Check originated with
Smalltalk, which is a late binding object-oriented language supporting
reflection. Writing a framework for C requires solving some special
problems that frameworks for Smalltalk, Java or Python don't have to
face. In all of those language, the worst that a unit test can do is
fail miserably, throwing an exception of some sort. In C, a unit test
is just as likely to trash its address space as it is to fail to meet
its test requirements, and if the test framework sits in the same
address space, goodbye test framework.
To solve this problem, Check uses the @code{fork()} system call to
create a new address space in which to run each unit test, and then
uses message queues to send information on the testing process back to
the test framework. That way, your unit test can do all sorts of
nasty things with pointers, and throw a segmentation fault, and the
test framework will happily note a unit test error, and chug along.
The Check framework is also designed to play happily with common
development environments for C programming. The author designed Check
around Autoconf/Automake (thus the name Check: @command{make check} is
the idiom used for testing with Autoconf/Automake). Note however that
Autoconf/Automake are NOT necessary to use Check; any build system
is sufficient. The test failure messages thrown up by Check use the
common idiom of @samp{filename:linenumber:message} used by @command{gcc}
and family to report problems in source code. With (X)Emacs, the output
of Check allows one to quickly navigate to the location of the unit test
that failed; presumably that also works in VI and IDEs.
@menu
* Other Frameworks for C::
@end menu
@node Other Frameworks for C, , Unit Testing in C, Unit Testing in C
@section Other Frameworks for C
@cindex other frameworks
@cindex frameworks
The authors know of the following additional unit testing frameworks
for C:
@table @asis
@item AceUnit
AceUnit (Advanced C and Embedded Unit) bills itself as a comfortable C
code unit test framework. It tries to mimic JUnit 4.x and includes
reflection-like capabilities. AceUnit can be used in resource
constraint environments, e.g. embedded software development, and
importantly it runs fine in environments where you cannot include a
single standard header file and cannot invoke a single standard C
function from the ANSI / ISO C libraries. It also has a Windows port.
It does not use forks to trap signals, although the authors have
expressed interest in adding such a feature. See the
@uref{http://aceunit.sourceforge.net/, AceUnit homepage}.
@item GNU Autounit
Much along the same lines as Check, including forking to run unit tests
in a separate address space (in fact, the original author of Check
borrowed the idea from @acronym{GNU} Autounit). @acronym{GNU} Autounit
uses GLib extensively, which means that linking and such need special
options, but this may not be a big problem to you, especially if you are
already using GTK or GLib. See the @uref{http://autounit.tigris.org/,
GNU Autounit homepage}.
@item cUnit
Also uses GLib, but does not fork to protect the address space of unit
tests. See the
@uref{http://web.archive.org/web/*/http://people.codefactory.se/~spotty/cunit/,
archived cUnit homepage}.
@item CUnit
Standard C, with plans for a Win32 GUI implementation. Does not
currently fork or otherwise protect the address space of unit tests.
In early development. See the @uref{http://cunit.sourceforge.net,
CUnit homepage}.
@item CuTest
A simple framework with just one .c and one .h file that you drop into
your source tree. See the @uref{http://cutest.sourceforge.net, CuTest
homepage}.
@item CppUnit
The premier unit testing framework for C++; you can also use it to test C
code. It is stable, actively developed, and has a GUI interface. The
primary reasons not to use CppUnit for C are first that it is quite
big, and second you have to write your tests in C++, which means you
need a C++ compiler. If these don't sound like concerns, it is
definitely worth considering, along with other C++ unit testing
frameworks. See the
@uref{http://cppunit.sourceforge.net/cppunit-wiki, CppUnit homepage}.
@item embUnit
embUnit (Embedded Unit) is another unit test framework for embedded
systems. This one appears to be superseded by AceUnit.
@uref{https://sourceforge.net/projects/embunit/, Embedded Unit
homepage}.
@item MinUnit
A minimal set of macros and that's it! The point is to
show how easy it is to unit test your code. See the
@uref{http://www.jera.com/techinfo/jtns/jtn002.html, MinUnit
homepage}.
@item CUnit for Mr. Ando
A CUnit implementation that is fairly new, and apparently still in
early development. See the
@uref{http://park.ruru.ne.jp/ando/work/CUnitForAndo/html/, CUnit for
Mr. Ando homepage}.
@end table
This list was last updated in March 2008. If you know of other C unit
test frameworks, please send an email plus description to
@email{check-devel AT lists.sourceforge.net} and we will add the entry
to this list.
It is the authors' considered opinion that forking or otherwise
trapping and reporting signals is indispensable for unit testing (but
it probably wouldn't be hard to add that to frameworks without that
feature). Try 'em all out: adapt this tutorial to use all of the
frameworks above, and use whichever you like. Contribute, spread the
word, and make one a standard. Languages such as Java and Python are
fortunate to have standard unit testing frameworks; it would be desirable
that C have one as well.
@node Tutorial, Advanced Features, Unit Testing in C, Top
@chapter Tutorial: Basic Unit Testing
This tutorial will use the JUnit
@uref{http://junit.sourceforge.net/doc/testinfected/testing.htm, Test
Infected} article as a starting point. We will be creating a library
to represent money, @code{libmoney}, that allows conversions between
different currency types. The development style will be ``test a
little, code a little'', with unit test writing preceding coding.
This constantly gives us insights into module usage, and also makes
sure we are constantly thinking about how to test our code.
@menu
* How to Write a Test::
* Setting Up the Money Build Using Autotools::
* Setting Up the Money Build Using CMake::
* Test a Little::
* Creating a Suite::
* SRunner Output::
@end menu
@node How to Write a Test, Setting Up the Money Build Using Autotools, Tutorial, Tutorial
@section How to Write a Test
Test writing using Check is very simple. The file in which the checks
are defined must include @file{check.h} as so:
@example
@verbatim
#include <check.h>
@end verbatim
@end example
The basic unit test looks as follows:
@example
@verbatim
START_TEST (test_name)
{
/* unit test code */
}
END_TEST
@end verbatim
@end example
The @code{START_TEST}/@code{END_TEST} pair are macros that setup basic
structures to permit testing. It is a mistake to leave off the
@code{END_TEST} marker; doing so produces all sorts of strange errors
when the check is compiled.
@node Setting Up the Money Build Using Autotools, Setting Up the Money Build Using CMake, How to Write a Test, Tutorial
@section Setting Up the Money Build Using Autotools
Since we are creating a library to handle money, we will first create
an interface in @file{money.h}, an implementation in @file{money.c},
and a place to store our unit tests, @file{check_money.c}. We want to
integrate these core files into our build system, and will need some
additional structure. To manage everything we'll use Autoconf,
Automake, and friends (collectively known as Autotools) for this
example. Note that one could do something similar with ordinary
Makefiles, or any other build system. It is in the authors' opinion that
it is generally easier to use Autotools than bare Makefiles, and they
provide built-in support for running tests.
Note that this is not the place to explain how Autotools works. If
you need help understanding what's going on beyond the explanations
here, the best place to start is probably Alexandre Duret-Lutz's
excellent
@uref{http://www.lrde.epita.fr/~adl/autotools.html,
Autotools tutorial}.
The examples in this section are part of the Check distribution; you
don't need to spend time cutting and pasting or (worse) retyping them.
Locate the Check documentation on your system and look in the
@samp{example} directory. The standard directory for GNU/Linux
distributions should be @samp{/usr/share/doc/check/example}. This
directory contains the final version reached the end of the tutorial. If
you want to follow along, create backups of @file{money.h},
@file{money.c}, and @file{check_money.c}, and then delete the originals.
We set up a directory structure as follows:
@example
@verbatim
.
|-- Makefile.am
|-- README
|-- configure.ac
|-- src
| |-- Makefile.am
| |-- main.c
| |-- money.c
| `-- money.h
`-- tests
|-- Makefile.am
`-- check_money.c
@end verbatim
@end example
Note that this is the output of @command{tree}, a great directory
visualization tool. The top-level @file{Makefile.am} is simple; it
merely tells Automake how to process sub-directories:
@example
@verbatim
SUBDIRS = src . tests
@end verbatim
@end example
Note that @code{tests} comes last, because the code should be testing
an already compiled library. @file{configure.ac} is standard Autoconf
boilerplate, as specified by the Autotools tutorial and as suggested
by @command{autoscan}.
@file{src/Makefile.am} builds @samp{libmoney} as a Libtool archive,
and links it to an application simply called @command{main}. The
application's behavior is not important to this tutorial; what's
important is that none of the functions we want to unit test appear in
@file{main.c}; this probably means that the only function in
@file{main.c} should be @code{main()} itself. In order to test the
whole application, unit testing is not appropriate: you should use a
system testing tool like Autotest. If you really want to test
@code{main()} using Check, rename it to something like
@code{_myproject_main()} and write a wrapper around it.
The primary build instructions for our unit tests are in
@file{tests/Makefile.am}:
@cartouche
@example
@verbatiminclude example/tests/Makefile.am
@end example
@end cartouche
@code{TESTS} tells Automake which test programs to run for
@command{make check}. Similarly, the @code{check_} prefix in
@code{check_PROGRAMS} actually comes from Automake; it says to build
these programs only when @command{make check} is run. (Recall that
Automake's @code{check} target is the origin of Check's name.) The
@command{check_money} test is a program that we will build from
@file{tests/check_money.c}, linking it against both
@file{src/libmoney.la} and the installed @file{libcheck.la} on our
system. The appropriate compiler and linker flags for using Check are
found in @code{@@CHECK_CFLAGS@@} and @code{@@CHECK_LIBS@@}, values
defined by the @code{AM_PATH_CHECK} macro.
Now that all this infrastructure is out of the way, we can get on with
development. @file{src/money.h} should only contain standard C header
boilerplate:
@cartouche
@example
@verbatiminclude example/src/money.1.h
@end example
@end cartouche
@file{src/money.c} should be empty, and @file{tests/check_money.c}
should only contain an empty @code{main()} function:
@cartouche
@example
@verbatiminclude example/tests/check_money.1.c
@end example
@end cartouche
Create the GNU Build System for the project and then build @file{main}
and @file{libmoney.la} as follows:
@example
@verbatim
$ autoreconf --install
$ ./configure
$ make
@end verbatim
@end example
(@command{autoreconf} determines which commands are needed in order
for @command{configure} to be created or brought up to date.
Previously one would use a script called @command{autogen.sh} or
@command{bootstrap}, but that practice is unnecessary now.)
Now build and run the @command{check_money} test with @command{make
check}. If all goes well, @command{make} should report that our tests
passed. No surprise, because there aren't any tests to fail. If you
have problems, make sure to see @ref{Supported Build Systems}.
This was tested on the isadora distribution of Linux Mint
GNU/Linux in November 2012, using Autoconf 2.65, Automake 1.11.1,
and Libtool 2.2.6b. Please report any problems to
@email{check-devel AT lists.sourceforge.net}.
@node Setting Up the Money Build Using CMake, Test a Little, Setting Up the Money Build Using Autotools, Tutorial
@section Setting Up the Money Build Using CMake
Since we are creating a library to handle money, we will first create
an interface in @file{money.h}, an implementation in @file{money.c},
and a place to store our unit tests, @file{check_money.c}. We want to
integrate these core files into our build system, and will need some
additional structure. To manage everything we'll use CMake for this
example. Note that one could do something similar with ordinary
Makefiles, or any other build system. It is in the authors' opinion that
it is generally easier to use CMake than bare Makefiles, and they
provide built-in support for running tests.
Note that this is not the place to explain how CMake works. If
you need help understanding what's going on beyond the explanations
here, the best place to start is probably the @uref{http://www.cmake.org,
CMake project's homepage}.
The examples in this section are part of the Check distribution; you
don't need to spend time cutting and pasting or (worse) retyping them.
Locate the Check documentation on your system and look in the
@samp{example} directory, or look in the Check source. If on a GNU/Linux
system the standard directory should be @samp{/usr/share/doc/check/example}.
This directory contains the final version reached the end of the tutorial. If
you want to follow along, create backups of @file{money.h},
@file{money.c}, and @file{check_money.c}, and then delete the originals.
We set up a directory structure as follows:
@example
@verbatim
.
|-- Makefile.am
|-- README
|-- CMakeLists.txt
|-- cmake
| |-- config.h.in
| |-- FindCheck.cmake
|-- src
| |-- CMakeLists.txt
| |-- main.c
| |-- money.c
| `-- money.h
`-- tests
|-- CMakeLists.txt
`-- check_money.c
@end verbatim
@end example
The top-level @file{CMakeLists.txt} contains the configuration checks
for available libraries and types, and also defines sub-directories
to process. The @file{cmake/FindCheck.cmake} file contains instructions
for locating Check on the system and setting up the build to use it.
If the system does not have pkg-config installed, @file{cmake/FindCheck.cmake}
may not be able to locate Check successfully. In this case, the install
directory of Check must be located manually, and the following line
added to @file{tests/CMakeLists.txt} (assuming Check was installed under
C:\\Program Files\\check:
@verbatim
set(CHECK_INSTALL_DIR "C:/Program Files/check")
@end verbatim
Note that @code{tests} comes last, because the code should be testing
an already compiled library.
@file{src/CMakeLists.txt} builds @samp{libmoney} as an archive,
and links it to an application simply called @command{main}. The
application's behavior is not important to this tutorial; what's
important is that none of the functions we want to unit test appear in
@file{main.c}; this probably means that the only function in
@file{main.c} should be @code{main()} itself. In order to test the
whole application, unit testing is not appropriate: you should use a
system testing tool like Autotest. If you really want to test
@code{main()} using Check, rename it to something like
@code{_myproject_main()} and write a wrapper around it.
Now that all this infrastructure is out of the way, we can get on with
development. @file{src/money.h} should only contain standard C header
boilerplate:
@cartouche
@example
@verbatiminclude example/src/money.1.h
@end example
@end cartouche
@file{src/money.c} should be empty, and @file{tests/check_money.c}
should only contain an empty @code{main()} function:
@cartouche
@example
@verbatiminclude example/tests/check_money.1.c
@end example
@end cartouche
Create the CMake Build System for the project and then build @file{main}
and @file{libmoney.la} as follows for Unix-compatible systems:
@example
@verbatim
$ cmake .
$ make
@end verbatim
@end example
and for MSVC on Windows:
@example
@verbatim
$ cmake -G "NMake Makefiles" .
$ nmake
@end verbatim
@end example
Now build and run the @command{check_money} test, with either @command{make
test} on a Unix-compatible system or @command{nmake test} if on Windows using MSVC.
If all goes well, the command should report that our tests
passed. No surprise, because there aren't any tests to fail.
This was tested on Windows 7 using CMake 2.8.12.1 and MSVC 16.00.30319.01/
Visual Studios 10 in February 2014. Please report any problems to
@email{check-devel AT lists.sourceforge.net}.
@node Test a Little, Creating a Suite, Setting Up the Money Build Using CMake, Tutorial
@section Test a Little, Code a Little
The @uref{http://junit.sourceforge.net/doc/testinfected/testing.htm,
Test Infected} article starts out with a @code{Money} class, and so
will we. Of course, we can't do classes with C, but we don't really
need to. The Test Infected approach to writing code says that we
should write the unit test @emph{before} we write the code, and in
this case, we will be even more dogmatic and doctrinaire than the
authors of Test Infected (who clearly don't really get this stuff,
only being some of the originators of the Patterns approach to
software development and OO design).
Here are the changes to @file{check_money.c} for our first unit test:
@cartouche
@example
@verbatiminclude check_money.1-2.c.diff
@end example
@end cartouche
@findex ck_assert_int_eq
@findex ck_assert_str_eq
A unit test should just chug along and complete. If it exits early,
or is signaled, it will fail with a generic error message. (Note: it
is conceivable that you expect an early exit, or a signal and there is
functionality in Check to specifically assert that we should expect a
signal or an early exit.) If we want to get some information
about what failed, we need to use some calls that will point out a failure.
Two such calls are @code{ck_assert_int_eq} (used to determine if two integers
are equal) and @code{ck_assert_str_eq} (used to determine if two null terminated
strings are equal). Both of these functions (actually macros) will signal an error
if their arguments are not equal.
@findex ck_assert
An alternative to using @code{ck_assert_int_eq} and @code{ck_assert_str_eq}
is to write the expression under test directly using @code{ck_assert}.
This takes one Boolean argument which must be True for the check to pass.
The second test could be rewritten as follows:
@example
@verbatim
ck_assert(strcmp (money_currency (m), "USD") == 0);
@end verbatim
@end example
@findex ck_assert_msg
@code{ck_assert} will find and report failures, but will not print any
user supplied message in the unit test result. To print a user defined
message along with any failures found, use @code{ck_assert_msg}. The first
argument is a Boolean argument. The remaining arguments support @code{varargs}
and accept @code{printf}-style format strings and arguments. This is especially
useful while debugging. For example, the second test could be rewritten as:
@example
@verbatim
ck_assert_msg(strcmp (money_currency (m), "USD") == 0,
"Was expecting a currency of USD, but found %s", money_currency (m));
@end verbatim
@end example
@findex ck_abort
@findex ck_abort_msg
If the Boolean argument is too complicated to elegantly express within
@code{ck_assert()}, there are the alternate functions @code{ck_abort()}
and @code{ck_abort_msg()} that unconditionally fail. The second test inside
@code{test_money_create} above could be rewritten as follows:
@example
@verbatim
if (strcmp (money_currency (m), "USD") != 0)
{
ck_abort_msg ("Currency not set correctly on creation");
}
@end verbatim
@end example
For your convenience ck_assert, which does not accept a user supplied message,
substitutes a suitable message for you. (This is also equivalent to
passing a NULL message to ck_assert_msg). So you could also
write a test as follows:
@example
@verbatim
ck_assert (money_amount (m) == 5);
@end verbatim
@end example
This is equivalent to:
@example
@verbatim
ck_assert_msg (money_amount (m) == 5, NULL);
@end verbatim
@end example
which will print the file, line number, and the message
@code{"Assertion 'money_amount (m) == 5' failed"} if
@code{money_amount (m) != 5}.
When we try to compile and run the test suite now using @command{make
check}, we get a whole host of compilation errors. It may seem a bit
strange to deliberately write code that won't compile, but notice what
we are doing: in creating the unit test, we are also defining
requirements for the money interface. Compilation errors are, in a
way, unit test failures of their own, telling us that the
implementation does not match the specification. If all we do is edit
the sources so that the unit test compiles, we are actually making
progress, guided by the unit tests, so that's what we will now do.
We will patch our header @file{money.h} as follows:
@cartouche
@example
@verbatiminclude money.1-2.h.diff
@end example
@end cartouche
Our code compiles now, and again passes all of the tests. However,
once we try to @emph{use} the functions in @code{libmoney} in the
@code{main()} of @code{check_money}, we'll run into more problems, as
they haven't actually been implemented yet.
@node Creating a Suite, SRunner Output, Test a Little, Tutorial
@section Creating a Suite
To run unit tests with Check, we must create some test cases,
aggregate them into a suite, and run them with a suite runner. That's
a bit of overhead, but it is mostly one-off. Here's a diff for the
new version of @file{check_money.c}. Note that we include stdlib.h to
get the definitions of @code{EXIT_SUCCESS} and @code{EXIT_FAILURE}.
@cartouche
@example
@verbatiminclude check_money.2-3.c.diff
@end example
@end cartouche
Most of the @code{money_suite()} code should be self-explanatory. We are
creating a suite, creating a test case, adding the test case to the
suite, and adding the unit test we created above to the test case.
Why separate this off into a separate function, rather than inline it
in @code{main()}? Because any new tests will get added in
@code{money_suite()}, but nothing will need to change in @code{main()}
for the rest of this example, so main will stay relatively clean and
simple.
Unit tests are internally defined as static functions. This means
that the code to add unit tests to test cases must be in the same
compilation unit as the unit tests themselves. This provides another
reason to put the creation of the test suite in a separate function:
you may later want to keep one source file per suite; defining a
uniquely named suite creation function allows you later to define a
header file giving prototypes for all the suite creation functions,
and encapsulate the details of where and how unit tests are defined
behind those functions. See the test program defined for Check itself
for an example of this strategy.
The code in @code{main()} bears some explanation. We are creating a
suite runner object of type @code{SRunner} from the @code{Suite} we
created in @code{money_suite()}. We then run the suite, using the
@code{CK_NORMAL} flag to specify that we should print a summary of the
run, and list any failures that may have occurred. We capture the
number of failures that occurred during the run, and use that to
decide how to return. The @code{check} target created by Automake
uses the return value to decide whether the tests passed or failed.
Now that the tests are actually being run by @command{check_money}, we
encounter linker errors again we try out @code{make check}. Try it
for yourself and see. The reason is that the @file{money.c}
implementation of the @file{money.h} interface hasn't been created
yet. Let's go with the fastest solution possible and implement stubs
for each of the functions in @code{money.c}. Here is the diff:
@cartouche
@example
@verbatiminclude money.1-3.c.diff
@end example
@end cartouche
Note that we @code{#include <stdlib.h>} to get the definition of
@code{NULL}. Now, the code compiles and links when we run @code{make
check}, but our unit test fails. Still, this is progress, and we can
focus on making the test pass.
@node SRunner Output, , Creating a Suite, Tutorial
@section SRunner Output
@findex srunner_run_all
@findex srunner_run
The functions to run tests in an @code{SRunner} are defined as follows:
@example
@verbatim
void srunner_run_all (SRunner * sr, enum print_output print_mode);
void srunner_run (SRunner *sr, const char *sname, const char *tcname,
enum print_output print_mode);
@end verbatim
@end example
Those functions do two things:
@enumerate
@item
They run all of the unit tests for the selected test cases defined for
the selected suites in the SRunner, and collect the results in the
SRunner. The determination of the selected test cases and suites
depends on the specific function used.
@code{srunner_run_all} will run all the defined test cases of all
defined suites except if the environment variables @code{CK_RUN_CASE}
or @code{CK_RUN_SUITE} are defined. If defined, those variables shall
contain the name of a test suite or a test case, defining in that way
the selected suite/test case.
@code{srunner_run} will run the suite/case selected by the
@code{sname} and @code{tcname} parameters. A value of @code{NULL}
in some of those parameters means ``any suite/case''.
@item
They print the results according to the @code{print_mode} specified.
@end enumerate
For SRunners that have already been run, there is also a separate
printing function defined as follows:
@example
@verbatim
void srunner_print (SRunner *sr, enum print_output print_mode);
@end verbatim
@end example
The enumeration values of @code{print_output} defined in Check that
parameter @code{print_mode} can assume are as follows:
@table @code
@vindex CK_SILENT
@item CK_SILENT
Specifies that no output is to be generated. If you use this flag, you
either need to programmatically examine the SRunner object, print
separately, or use test logging (@pxref{Test Logging}.)
@vindex CK_MINIMAL
@item CK_MINIMAL
Only a summary of the test run will be printed (number run, passed,
failed, errors).
@vindex CK_NORMAL
@item CK_NORMAL
Prints the summary of the run, and prints one message per failed
test.
@vindex CK_VERBOSE
@item CK_VERBOSE
Prints the summary, and one message per test (passed or failed)
@vindex CK_ENV
@vindex CK_VERBOSITY
@item CK_ENV
Gets the print mode from the environment variable @code{CK_VERBOSITY},
which can have the values "silent", "minimal", "normal", "verbose". If
the variable is not found or the value is not recognized, the print
mode is set to @code{CK_NORMAL}.
@vindex CK_SUBUNIT
@item CK_SUBUNIT
Prints running progress through the @uref{https://launchpad.net/subunit/,
subunit} test runner protocol. See 'subunit support' under the Advanced Features section for more information.
@end table
With the @code{CK_NORMAL} flag specified in our @code{main()}, let's
rerun @code{make check} now. The output from the unit test is as follows:
@example
@verbatim
Running suite(s): Money
0%: Checks: 1, Failures: 1, Errors: 0
check_money.c:9:F:Core:test_money_create:0: Assertion 'money_amount (m)==5' failed:
money_amount (m)==0, 5==5
FAIL: check_money
=====================================================
1 of 1 test failed
Please report to check-devel AT lists.sourceforge.net
=====================================================
@end verbatim
@end example
Note that the output from @code{make check} prior to Automake 1.13 will
be the output of the unit test program. Starting with 1.13 Automake will
run all unit test programs concurrently and store the output in
log files. The output listed above should be present in a log file.
The first number in the summary line tells us that 0% of our tests
passed, and the rest of the line tells us that there was one check in
total, and of those checks, one failure and zero errors. The next
line tells us exactly where that failure occurred, and what kind of
failure it was (P for pass, F for failure, E for error).
After that we have some higher level output generated by Automake: the
@code{check_money} program failed, and the bug-report address given in
@file{configure.ac} is printed.
Let's implement the @code{money_amount} function, so that it will pass
its tests. We first have to create a Money structure to hold the
amount, and then implement the function to return the correct amount:
@cartouche
@example
@verbatiminclude money.3-4.c.diff
@end example
@end cartouche
We will now rerun make check and@dots{} what's this? The output is
now as follows:
@example
@verbatim
Running suite(s): Money
0%: Checks: 1, Failures: 0, Errors: 1
check_money.c:5:E:Core:test_money_create:0: (after this point)
Received signal 11 (Segmentation fault)
@end verbatim
@end example
@findex mark_point
What does this mean? Note that we now have an error, rather than a
failure. This means that our unit test either exited early, or was
signaled. Next note that the failure message says ``after this
point''; This means that somewhere after the point noted
(@file{check_money.c}, line 5) there was a problem: signal 11 (a.k.a.
segmentation fault). The last point reached is set on entry to the
unit test, and after every call to the @code{ck_assert()},
@code{ck_abort()}, @code{ck_assert_int_*()}, @code{ck_assert_str_*()},
or the special function @code{mark_point()}. For example, if we wrote some test
code as follows:
@example
@verbatim
stuff_that_works ();
mark_point ();
stuff_that_dies ();
@end verbatim
@end example
then the point returned will be that marked by @code{mark_point()}.
The reason our test failed so horribly is that we haven't implemented
@code{money_create()} to create any @code{Money}. We'll go ahead and
implement that, the symmetric @code{money_free()}, and
@code{money_currency()} too, in order to make our unit test pass again,
here is a diff:
@cartouche
@example
@verbatiminclude money.4-5.c.diff
@end example
@end cartouche
@node Advanced Features, Supported Build Systems, Tutorial, Top
@chapter Advanced Features
What you've seen so far is all you need for basic unit testing. The
features described in this section are additions to Check that make it
easier for the developer to write, run, and analyze tests.
@menu
* Convenience Test Functions::
* Running Multiple Cases::
* No Fork Mode::
* Test Fixtures::
* Multiple Suites in one SRunner::
* Selective Running of Tests::
* Selecting Tests by Suite or Test Case::
* Selecting Tests Based on Arbitrary Tags::
* Testing Signal Handling and Exit Values::
* Looping Tests::
* Test Timeouts::
* Determining Test Coverage::
* Finding Memory Leaks::
* Test Logging::
* Subunit Support::
@end menu
@node Convenience Test Functions, Running Multiple Cases, Advanced Features, Advanced Features
@section Convenience Test Functions
Using the @code{ck_assert} function for all tests can lead to lot of
repetitive code that is hard to read. For your convenience Check
provides a set of functions (actually macros) for testing often used
conditions.
@findex check_set_max_msg_size
@vindex CK_MAX_MSG_SIZE
The typical size of an assertion message is less than 80 bytes.
However, some of the functions listed below can generate very large messages
(up to 4GB allocations were seen in the wild).