aboutsummaryrefslogtreecommitdiff
path: root/src/doxy/unittest.dox
blob: a3f1c1a944ce0c9c79d597e3330d2935dd41ba50 (plain)
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
/*
 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */

/**
 *@page howto_unittest Writing Unit Tests For Your Programs
 *
 * Libbu++ uses it's own simple and flexible unit testing framework, and you can
 * too!  Unit testing is a fairly simple concept.  You create many small tests
 * that ensure that each individual component of a program is working as it
 * should.  These make it easy to test code as it's designed, and even helps to
 * ensure that your code continues to work as changes are made in the future.
 *
 * There are two main ways of writing unit test "suites" or pagkages with
 * libbu++:  Using the mkunit unit test compiler or by using the Bu::UnitSuite
 * class directly.  Both of these will be dicussed below, but the mkunit method
 * is definately recommended.
 *
 *@section mkunit Using mkunit to create Unit Test Suites
 *
 * Using mkunit is definately the easiest way to go, the format is very basic,
 * and almost all c++ constructs work exactly as you would expect.  First, the
 * mkunit program itself is included with libbu++ and built when the library is
 * built.  When you run mkunit on a .unit file it produces a matching .cpp file.
 * You should avoid editing the generated .cpp file since it will be overwritten
 * by the next run of mkunit.  To make debugging easier mkunit takes advantage
 * of standard preprocessor macros to make debuggers and compilers treat the
 * .unit file as the original source file, all errors will refer to that file.
 *
 * There are two new constructs that you can take advantage of in a .unit file:
 * - suite: This identifier defines a suite of tests, each .unit file needs at
 *   least one of these.  suite is followed by a { } block that may contain
 *   standard c++ code as well as test identifiers.  This becomes the UnitSuite
 *   child class.
 * - test: This identifier defines a test within the suite, and is followed by
 *   a { } block of code that is run for that test.  This becomes a function.
 *
 * A simple example will help illustrate this:
 *@code
#include <stdio.h>

suite Math
{
	test arithmetic
	{
		unitTest( 5*5 == 25 );
		unitTest( 25/5 == 5 );
		unitTest( 5+5 == 10 );
		// etc...
	}
}
 @endcode
 *
 * This example creates one test suite named Math, and one test named arithmetic
 * which tests the computer's ability to do simple arithmetic.  The macro
 * unitTest(...) checks the contained code, if the expression evaluetes to true
 * then the test continues, if not it fails immediately, exists, and reports
 * what expression caused it to fail, and what line number it happened on.
 * 
 * Also available is the macro unitFailed("...") which will cause the test to
 * immediately fail, and the reason given will be the textual message provided.
 *
 * When using the mkunit method, you shouldn't define a main function, this is
 * automatically done for you.
 *
 * Compiling a mkunit style unit test suite is fairly easy too.  You basically
 * need the following:
 *@code
mkunit mysuite.unit mysuite.cpp
g++ mysuite.cpp -o mysuite -lbu++
@endcode
 * This will produce a ready to use executable that will run all tests in the
 * suite and report success or failure, and provide a nice summary at the end.
 * Each test suite also supports a rich set of command line options to get more
 * information, control which tests are run, and control output.
 *
 *@section unitsuite_features UnitSuite features for everyone
 * There are a number of features that you can take advantage of no matter what
 * method you used to design your unit test suite.  One of them is the progress
 * meter.  For tests that are going to take a noticable amount of time, or even
 * all tests that have more than one step, you can use the functions:
 *  - Bu::UnitSuite::setStepCount - to set the number of steps that will be
 *    performed by the test.  This is effectively arbitrary and just sets the
 *    upper limit for the progress indicator.  For example, if you're going to
 *    perform a nested loop with 100 iterations in the outer and 250 on the
 *    inner you may call setStepCount( 100*250 ) at the begining of the test.
 *  - Bu::UnitSuite::incProgress - Increment the progress counter by one.
 *    In the above example if you placed this function call at the end of the
 *    innermost loop you would get a pleasant progress readout as the test
 *    proceeded.
 *
 * Here is a slightly more concrete example of the progress meter functions:
 *@code
suite Intensive
{
	test LongTest1
	{
		setStepCount( 100*250 );
		for( int iOuter = 0; iOuter < 100; ++iOuter )
		{
			for( int iInner = 0; iInner < 250; ++iInner )
			{
				doSomethingComplex( iOuter, iInner );
				incProgress();
			}
		}
	}
}
@endcode
 * To ensure that the progress meter doesn't use up an exorbatant amount of CPU
 * time in very tight loops the display will be updated at most every second,
 * and only when a call to incProgress is made.
 *
 *@todo Finish this page.
 */