OSDN Git Service

add rest of cookbook
[ccunit/ccunit.git] / doc / cookbook.dox
1 /* -*- Indented-Text -*- */
2 /* $Id$ */
3 /** @page cookbook CCUnit Cookbook
4
5 Here is a short cookbook to help you get started.
6
7 @section simple_test_case Simple Test Case
8
9 Tests in <b>CCUnit</b> can be run automatically.  They are
10 easy to set up and once you have written them, they are
11 always there to help you keep confidence in the quality of
12 your code.
13
14 To make a simple test, here is what you do:
15
16 <ol>
17 <li> Create a test function</li>
18 <li> When you want to check a value, call 
19      @link CCUNIT_ASSERT() CCUNIT_ASSERT(bool) @endlink
20      and pass a bool that is true if the test succeeds</li>
21 </ol>
22
23 For example, to test that the sum of two Moneys with the
24 same currency contains a value which is the sum of the
25 values of two Moneys, write:
26
27 @code
28 void testSimpleAdd ()
29 {
30   Money* m120JPY = Money_new (120, "JPY");
31   Money* m140JPY = Money_new (140, "JPY");
32   Money* expected = Money_new (260, "JPY");
33   Money* result = Money_add (m120JPY, m140JPY);
34   CCUNIT_ASSERT (Money_equals (expected, result));
35   Money_delete (m120JPY);
36   Money_delete (m140JPY);
37   Money_delete (expected);
38   Money_delete (result);
39 }
40 @endcode
41
42 That was a very simple test. Ordinarily, you'll have many
43 little test cases that you'll want to run on the same set of
44 objects. To do this, use a fixture.
45
46 @section fixture Fixture
47
48 What if you have two or more tests that operate on the same
49 similar set of objects?
50
51 Tests need to run against the background of a known set of
52 objects. This set of objects is called a test fixture. When
53 you are writing tests you will often find that you spend
54 more time writing the code to set up the fixture than you do
55 in actually testing values.
56
57 Often, you will be able to use the same fixture for sevral
58 different tests. Each case will send slightly different
59 messages or parameteres to the fixture and will check for
60 different results.
61
62 When you have a common fixture, here is what you do:
63
64 <ol>
65 <li>Create a @link CCUnitTestCase TestCase @endlink object</li>
66 <li>Add an global variable for each part of the fixture</li>
67 <li>Write <code>setUp()</code> function to initialize the valiables</li>
68 <li>Write <code>tearDown()</code> to release any permanent
69     resources you allocated in <code>setUp</code></li>
70 <li>Create a @link CCUnitTestFixture TestFixture @endlink object</li>
71 <li>Add test case objects to fixture object</li>
72 </ol>
73
74 For example, to write several test cases that want to work
75 with different combinations of 120 Japanese Yen, 140
76 Japanese Yen, and 28 US Dollars, first create a fixture:
77
78 @code
79 //** TEST CASE: Money test *\/
80
81 #include "Money.h"
82
83 static Money* s120JPY;
84 static Money* s140JPY;
85 static Money* s23USD;
86
87 void setUp_moneyTest ()
88 {
89   s120JPY = Money_new (120, "JPY");
90   s140JPY = Money_new (140, "JPY");
91   s23USD = Money_new (23, "USD");
92 }
93  
94 void tearDown_moneyTest ()
95 {
96   Money_delete (s120JPY);
97   Money_delete (s140JPY);
98   Money_delete (s23USD);
99 }
100
101 ...
102
103   CCUnitTestFixture* fixture;
104   fixture = ccunit_newTestFixture ("MoneyTest",
105                                    setUp_moneyTest,
106                                    tearDown_moneyTest);
107 @endcode
108
109 Once you have the Fixture in place, you can write as many
110 Test Cases as you'd like.
111
112 @section test_case Test Case
113
114 How do you write and invoke an individual test case when you
115 have a Fixture?
116
117 For example, to test the addition of a Money and a MoneyBag,
118 write:
119
120 @code
121 void testMoneyMoneyBag ()
122 {
123   Money* bag[] = { s260JPY, s28USD };
124   MoneyBag expected = MoneyBag_new (2, bag);
125   Money* subtotal = Money_add (s120JPY, s28USD);
126   Money* total = Money_add (subtotal, s140JPY);
127   CCUNIT_ASSERT (MoneyBag_equals (expected, total));
128   MoneyBag_delete (expected);
129   Money_delete (subtotal);
130   Money_delete (total);
131 }
132
133 ...
134
135   ccunit_addNewTestCase (fixture,
136                          "testSimpleAdd",
137                          "simple add test",
138                          testSympleAdd);
139   ccunit_addNewTestCase (fixture, 
140                          "testMoneyMoneyBag",
141                          "money bag test",
142                          testMoneyMoneyBag);
143 @endcode  
144
145 One may create and run objects for each test case like this:
146
147 @code
148   CCUnitTestResult* result;
149   result = ccunit_runTestFixture (fixture);
150 @endcode
151
152 When the test fixture is run, that specific test functions
153 will be run.  This is not a useful thing to do, however, as
154 no diagnostics will be displayed.  One will normally use a
155 @link ExecutingTest TestRunner @endlink (see below) to
156 display the results.
157
158 Once you have several tests, organize them into a suite.
159
160 @section suite Suite
161
162 How do you set up your tests so that you can run them all at once?
163
164 %CCUnit provides a @link CCUnitTestSuite TestSuite @endlink
165 module that runs any number of TestCases together.
166
167 You saw, above, how to run test fixture.
168
169 To create a suite of two or more tests, you do the following:
170
171 @code
172 CCUnitTestSuite* suite;
173 CCUnitTestFixture* fixture;
174 CCUnitTestResult* result;
175 suite = ccunit_newTestSuite ("Money test suite");
176 fixture = ccunit_newTestFixture ("Money Tests", setUp_moneyTest, tearDown_moneyTest);
177 ccunit_addNewTestCase (fixture,
178                        "testSimpleAdd", "simple add test", testSympleAdd);
179 ccunit_addNewTestCase (fixture, 
180                        "testMoneyMoneyBag", "money bag test", testMoneyMoneyBag);
181 ccunit_addTestFixture (suite, fixtuer);
182 result = ccunit_runTestSuite (suite, NULL);
183 @endcode         
184
185 @link CCUnitTestSuite TestSuites @endlink don't only have to
186 contain @link CCUnitTestFixture TestFixtures @endlink.  They
187 can contain any object that implements the @link CCUnitTest
188 Test @endlink interface.  For example, you can create a
189 @link CCUnitTestSuite TestSuite @endlink in your code and I
190 can create one in mine, and we can run them together by
191 creating a @link CCUnitTestSuite TestSuite @endlink that
192 contains both:
193
194 @code
195 CCUnitTestSuite* suite;
196 CCUnitTestResult* result;
197 suite = ccunit_newTestSuite ("suite");
198 ccunit_addTestSuite (suite, moneyTestSuite);
199 ccunit_addTestSuite (suite, complexNumberTestSuite);
200 result = ccunit_runTestSuite(suite, NULL);
201 @endcode
202
203
204 @section test_runner TestRunner
205
206 How do you run your tests and collect their results?
207
208 Once you have a test suite, you'll want to run it. %CCUnit
209 provides tools to define the suite to be run and to display
210 its results.  You make your suite accessible to a @link
211 CreatingTestSuite ccunit_makeSuite @endlink tool that generate a
212 creating test suite code.
213
214 For example, to make a MoneyTest suite available to a 
215 @link CreatingTestSuite ccunit_makeSuite @endlink, 
216 excute the following tool to 
217 MoneyTest.c:
218
219 @code
220 $ ccunit_makeSuite -f MoneyTest_suite -o makeMoneyTestSuite.c MoneyTest.c
221 @endcode
222
223 @anchor test_runner_code
224 To use the TestRunner, include the header files for the tests in Main.c:
225
226 @code
227 #include <ccunit/CCUnitTestRunner.h>
228 #include <ccunit/CCUnitTestSuite.h>
229 @endcode
230
231 And add a call to 
232 @link ccunit_addTestSuite()
233 ccunit_addTestSuite (CCUnitTestRunner*, CCUnitTestSuite *) @endlink 
234 in the <code>main()</code> function:
235
236 @code
237 extern CCUnitTestSuite* MoneyTest_suite(const char* name);
238
239 int main( int argc, char **argv)
240 {
241   CCUnitTestRunner* runner;
242   CCUnitTestSuite* suite;
243   runner = ccunit_newTestRunner (stdout);
244   suite = MoneyTest_suite ("MathTest Suite");
245   ccunit_runTestRunner (runner, suite);
246   return 0;
247 }
248 @endcode
249
250 The @link ExecutingTest TestRunner @endlink will run the tests. 
251 If all the tests pass, you'll get an informative message. 
252 If any fail, you'll get the following information:
253
254 <ul>
255 <li> The name of the source file that contains the test</li>
256 <li> The line number where the failure occurred</li>
257 <li> The name of the test case that failed</li>
258 <li> All of the text inside the call to
259      <code>CCUNIT_ASSERT ()</code> which detected the failure</li>
260 </ul>
261
262 @section helper_macros Helper Tool
263
264 As you might have noticed, implementing the fixture
265 <code>suite ()</code> function is a repetitive and error
266 prone task. A @ref CreatingTestSuite set of functions and
267 command have been created to automatically implements the
268 <code>suite()</code> method.
269
270 The following code is a rewrite of MoneyTest using those command:
271
272 @code
273 #include <cppunit/CCUnitAssert.h>
274 @endcode
275
276 First, you declare the fixture, passing the test fixture
277 name to the javaDoc style comment, which consist of a
278 C-style comment block starting with two <tt>*</tt>'s:
279
280 @code
281 //** test case: Money test *\/
282 @endcode
283
284 The suite created by the <code>ccunit_suite()</code>
285 function is specified <code>-f</code> option of command
286 <code>ccunit_makeSuite</code>.  Then, you define each test
287 case of the fixture with prefix <code>test</code>,
288 <code>setUp</code>, <code>tearDown</code>:
289
290 @code
291 static Money* s120JPY;
292 static Money* s140JPY;
293 static Money* s260JPY;
294 static Money* s23USD;
295
296 void setUp_MathTest ()
297 {
298   s120JPY = Money_new (120, "JPY");
299   s140JPY = Money_new (140, "JPY");
300   s260JPY = Money_new (260, "JPY");
301   s23USD = Money_new (23, "USD");
302 }
303
304 void tearDown_Mathtest ()
305 {
306   Money_delete (s120JPY);
307   Money_delete (s140JPY);
308   Money_delete (s260JPY);
309   Money_delete (s23USD);
310 }
311
312 //** simple add test *\/
313 void test_simpleAdd ()
314 {
315   Money* result = Money_add (s120JPY, s140JPY);
316   CCUNIT_ASSERT (Money_equals (s260JPY, result));
317   Money_delete (result);
318 }
319
320 //** money bug test *\/
321 void test_moneyBag()
322 {
323   Money* bag[] = { s260JPY, s28USD };
324   MoneyBag expected = MoneyBag_new (2, bag);
325   Money* subtotal = Money_add (s120JPY, s28USD);
326   Money* total = Money_add (subtotal, s140JPY);
327   CCUNIT_ASSERT (MoneyBag_equals (expected, total));
328   MoneyBag_delete (expected);
329   Money_delete (subtotal);
330   Money_delete (total);
331 }
332 @endcode
333
334 Finally, you end the fixture declaration:
335
336 @code
337 //** end test case *\/
338 @endcode
339
340 To generate creating suite function code, run
341 <code>ccunit_makeSuite</code> tool.
342
343 @code
344 $ ccunit_makeSuite MoneyTest.c
345
346 #include <ccunit/CCUnitTestSuite.h>
347
348 static CCUnitTestSuite* newSuite_001 (const char* name);
349 //* test fixture: Money test *\/
350 //* setUp_MathTest *\/
351 extern void setUp_MathTest ();
352 //* tearDown_Mathtest *\/
353 extern void tearDown_Mathtest ();
354 //* simple add test *\/
355 extern void test_simpleAdd ();
356 //* money bug test *\/
357 extern void test_moneyBag ();
358
359 static CCUnitTestSuite* newSuite_001 (const char* name)
360 {
361   CCUnitTestSuite* suite;
362   suite = ccunit_newTestSuite (name);
363   {
364     CCUnitTestFixture* testFixture;
365     testFixture = ccunit_newTestFixture ("Money test",
366                                          setUp_MathTest,
367                                          tearDown_Mathtest);
368     if (testFixture != NULL)
369       ccunit_addTestFixture (suite, testFixture);
370     {
371       CCUnitTestCase* newCase;
372       newCase = ccunit_newTestCase ("test_simpleAdd",
373                                     "simple add test",
374                                     test_simpleAdd);
375       if (newCase != NULL)
376         ccunit_addTestCase (testFixture, newCase);
377     }
378     {
379       CCUnitTestCase* newCase;
380       newCase = ccunit_newTestCase ("test_moneyBag",
381                                     "money bug test",
382                                     test_moneyBag);
383       if (newCase != NULL)
384         ccunit_addTestCase (testFixture, newCase);
385     }
386   }
387
388   return suite;
389 }
390
391
392 CCUnitTestSuite* ccunit_suite (const char* name)
393 {
394   return newSuite_001 (name);
395 }
396 $
397 @endcode
398
399 @section post_build_check Post-build check
400
401 Now that we have our unit tests running, how about
402 integrating unit testing to our build process ?
403
404 To do that, the application must returns a value different than 0 to indicate that
405 there was an error.
406
407 @link ccunit_runTestRunner() ccunit_runTestRunner() @endlink returns 
408 a integer indicating if the run was successful.
409
410 Updating our main programm, we obtains:
411 @code
412 #include <ccunit/CCUnitTestRunner.h>
413
414 int main (int argc, char** argv)
415 {
416   CCUnitTestRunner* runner;
417   CCUnitTestSuite* suite;
418   int wasSucessful;
419   runner = ccunit_newTestRunner (stdout);
420   suite = ccunit_suite ();
421   wasSucessful = ccunit_runTestRunner (runner, suite);
422   return wasSucessful;
423 }
424 @endcode
425
426 Now, you need to run your application after compilation.
427
428 */