From: cpickett Date: Fri, 13 Oct 2006 03:49:07 +0000 (+0000) Subject: * Converted the next section of chapter 3 to Texinfo. X-Git-Tag: 0.10.0~839 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3418df5274ec78bac171dc9e11c5077e3c8749c1;p=check * Converted the next section of chapter 3 to Texinfo. * And actually, below, chapter 3 wasn't completed. The previous section _in_ chapter 3 was completed. git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@314 64e312b2-a51f-0410-8e61-82d0ca0eb02a --- diff --git a/doc/check.texi b/doc/check.texi index b3bc8c4..093207d 100644 --- a/doc/check.texi +++ b/doc/check.texi @@ -12,7 +12,8 @@ This manual is for Check (version @value{VERSION}, @value{UPDATED}), a unit test framework for C programs. -Copyright @copyright{} 2001--2006 Arien Malec and Chris Pickett +Copyright @copyright{} 2001--2006 Fredrik Hugosson, Robert Lemmen, +Arien Malec, and Chris Pickett. @quotation Permission is granted to copy, distribute and/or modify this document @@ -71,7 +72,8 @@ Tutorial: Basic Unit Testing * How to Write a Test:: * Setting Up the Money Build:: -* Setting Up the Money Tests:: +* Test a Little:: +* Creating a Suite:: Copying This Manual @@ -250,7 +252,8 @@ sure we are constantly thinking about how to test our code. @menu * How to Write a Test:: * Setting Up the Money Build:: -* Setting Up the Money Tests:: +* Test a Little:: +* Creating a Suite:: @end menu @node How to Write a Test, Setting Up the Money Build, Tutorial, Tutorial @@ -280,7 +283,7 @@ 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, Setting Up the Money Tests, How to Write a Test, Tutorial +@node Setting Up the Money Build, Test a Little, How to Write a Test, Tutorial @section Setting Up the Money Build Since we are creating a library to handle money, we will first create @@ -411,8 +414,185 @@ GNU/Linux (etch) in March 2006, using Autoconf 2.59, Automake 1.9.6, and Libtool 1.5.22. Please report any problems to @email{check-devel@@lists.sourceforge.net}. -@node Setting Up the Money Tests, , Setting Up the Money Build, Tutorial -@section Setting Up the Money Tests +@node Test a Little, Creating a Suite, Setting Up the Money Build, 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 is our first unit test: +@example +@verbatim +START_TEST (test_money_create) +{ + Money *m; + m = money_create (5, "USD"); + fail_unless (money_amount (m) == 5, + "Amount not set correctly on creation"); + fail_unless (strcmp (money_currency (m), "USD") == 0, + "Currency not set correctly on creation"); + money_free(m); +} +END_TEST +@end verbatim +@end example + +@findex fail_unless() +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. There is +currently nothing in Check to specifically assert that we should +expect either --- if that is valuable, it may be worth while adding to +Check.) If we want to get some information about what failed, we need +to use the @code{fail_unless()} function. The function (actually a +macro) takes a first Boolean argument, and an error message to send if +the condition is not true. + +@findex fail() +If the Boolean argument is too complicated to elegantly express within +@code{fail_unless()}, there is an alternate function @code{fail()} +that unconditionally fails. The second test inside +@code{test_money_create} above could be rewritten as follows: +@example +@verbatim + if (strcmp (money_currency (m), "USD") != 0) + { + fail ("Currency not set correctly on creation"); + } +@end verbatim +@end example + +@findex fail_if() +There is also a @code{fail_if()} function, which is the +inverse of @code{fail_unless()}. Using it, the above test then +looks like this: +@example +@verbatim + fail_if (strcmp (money_currency (m), "USD") != 0, + "Currency not set correctly on creation"); +@end verbatim +@end example + +For your convenience all fail functions also accepts NULL as the msg +argument and substitutes a suitable message for you. So you could also +write a test as follows: +@example +@verbatim + fail_unless (money_amount (m) == 5, NULL); +@end verbatim +@end example + +This is equivalent to: +@example +@verbatim + fail_unless (money_amount (m) == 5, + "Assertion 'money_amount (m) == 5' failed"); +@end verbatim +@end example + +All fail functions also support @code{varargs} and accept +@code{printf}-style format strings and arguments. This is especially +useful while debugging. With @code{printf}-style formatting the +message could look like this: +@example +@verbatim + fail_unless(money_amount (m) == 5, + "Amount was %d, instead of 5", money_amount (m)); +@end verbatim +@end example + +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 add the following to our header @file{money.h}: +@example +@verbatim +typedef struct Money Money; + +Money *money_create (int amount, char *currency); + +int money_amount (Money * m); + +char *money_currency (Money * m); + +void money_free (Money * m); +@end verbatim +@end example + +and the following to the top of @file{check_money.c}: +@example +@verbatim +#include +#include "../src/money.h" +@end verbatim +@end example + +@c FIXME: this should be introduced after something fails, like main() +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, , Test a Little, Tutorial +@section Create a Suite + +@c FIXME: should come after the bit where we try to call them and +@c FIXME: it fails. +The tests aren't actually being run by @command{check_money}, and if +we did try to run them we would encounter further errors; the +@file{money.c} implementation of the @file{money.h} interface hasn't +been defined yet. Let's create the @code{Money} type and stubs for +each of the functions: +@example +@verbatim +#include +#include "money.h" + +struct Money +{ + int amount; + char *currency; +}; + +Money * +money_create (int amount, char *currency) +{ + return NULL; +} + +int +money_amount (Money * m) +{ + return 0; +} + +char * +money_currency (Money * m) +{ + return NULL; +} + +void +money_free (Money * m) +{ + return; +} +@end verbatim +@end example @node AM_PATH_CHECK, Copying This Manual, Tutorial, Top @chapter AM_PATH_CHECK