|
Packit |
3adb1e |
Originally obtained from "http://cutest.sourceforge.net/" version 1.4.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
HOW TO USE
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
You can use CuTest to create unit tests to drive your development
|
|
Packit |
3adb1e |
in the style of Extreme Programming. You can also add unit tests to
|
|
Packit |
3adb1e |
existing code to ensure that it works as you suspect.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Your unit tests are an investment. They let you to change your
|
|
Packit |
3adb1e |
code and add new features confidently without worrying about
|
|
Packit |
3adb1e |
accidentally breaking earlier features.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
LICENSING
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Copyright (c) 2003 Asim Jalis
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
This software is provided 'as-is', without any express or implied
|
|
Packit |
3adb1e |
warranty. In no event will the authors be held liable for any damages
|
|
Packit |
3adb1e |
arising from the use of this software.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Permission is granted to anyone to use this software for any purpose,
|
|
Packit |
3adb1e |
including commercial applications, and to alter it and redistribute it
|
|
Packit |
3adb1e |
freely, subject to the following restrictions:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
1. The origin of this software must not be misrepresented; you must not
|
|
Packit |
3adb1e |
claim that you wrote the original software. If you use this software in
|
|
Packit |
3adb1e |
a product, an acknowledgment in the product documentation would be
|
|
Packit |
3adb1e |
appreciated but is not required.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
2. Altered source versions must be plainly marked as such, and must not
|
|
Packit |
3adb1e |
be misrepresented as being the original software.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
3. This notice may not be removed or altered from any source
|
|
Packit |
3adb1e |
distribution.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
GETTING STARTED
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
To add unit testing to your C code the only files you need are
|
|
Packit |
3adb1e |
CuTest.c and CuTest.h.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuTestTest.c and AllTests.c have been included to provide an
|
|
Packit |
3adb1e |
example of how to write unit tests and then how to aggregate them
|
|
Packit |
3adb1e |
into suites and into a single AllTests.c file. Suites allow you
|
|
Packit |
3adb1e |
to put group tests into logical sets. AllTests.c combines all the
|
|
Packit |
3adb1e |
suites and runs them.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
You should not have to look inside CuTest.c. Looking in
|
|
Packit |
3adb1e |
CuTestTest.c and AllTests.c (for example usage) should be
|
|
Packit |
3adb1e |
sufficient.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
After downloading the sources, run your compiler to create an
|
|
Packit |
3adb1e |
executable called AllTests.exe. For example, if you are using
|
|
Packit |
3adb1e |
Windows with the cl.exe compiler you would type:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
cl.exe AllTests.c CuTest.c CuTestTest.c
|
|
Packit |
3adb1e |
AllTests.exe
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
This will run all the unit tests associated with CuTest and print
|
|
Packit |
3adb1e |
the output on the console. You can replace cl.exe with gcc or
|
|
Packit |
3adb1e |
your favorite compiler in the command above.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
DETAILED EXAMPLE
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Here is a more detailed example. We will work through a simple
|
|
Packit |
3adb1e |
test first exercise. The goal is to create a library of string
|
|
Packit |
3adb1e |
utilities. First, lets write a function that converts a
|
|
Packit |
3adb1e |
null-terminated string to all upper case.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Ensure that CuTest.c and CuTest.h are accessible from your C
|
|
Packit |
3adb1e |
project. Next, create a file called StrUtil.c with these
|
|
Packit |
3adb1e |
contents:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "CuTest.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
char* StrToUpper(char* str) {
|
|
Packit |
3adb1e |
return str;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
void TestStrToUpper(CuTest *tc) {
|
|
Packit |
3adb1e |
char* input = strdup("hello world");
|
|
Packit |
3adb1e |
char* actual = StrToUpper(input);
|
|
Packit |
3adb1e |
char* expected = "HELLO WORLD";
|
|
Packit |
3adb1e |
CuAssertStrEquals(tc, expected, actual);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuite* StrUtilGetSuite() {
|
|
Packit |
3adb1e |
CuSuite* suite = CuSuiteNew();
|
|
Packit |
3adb1e |
SUITE_ADD_TEST(suite, TestStrToUpper);
|
|
Packit |
3adb1e |
return suite;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Create another file called AllTests.c with these contents:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "CuTest.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuite* StrUtilGetSuite();
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
void RunAllTests(void) {
|
|
Packit |
3adb1e |
CuString *output = CuStringNew();
|
|
Packit |
3adb1e |
CuSuite* suite = CuSuiteNew();
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuiteAddSuite(suite, StrUtilGetSuite());
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuSuiteRun(suite);
|
|
Packit |
3adb1e |
CuSuiteSummary(suite, output);
|
|
Packit |
3adb1e |
CuSuiteDetails(suite, output);
|
|
Packit |
3adb1e |
printf("%s\n", output->buffer);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
int main(void) {
|
|
Packit |
3adb1e |
RunAllTests();
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Then type this on the command line:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
gcc AllTests.c CuTest.c StrUtil.c
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
to compile. You can replace gcc with your favorite compiler.
|
|
Packit |
3adb1e |
CuTest should be portable enough to handle all Windows and Unix
|
|
Packit |
3adb1e |
compilers. Then to run the tests type:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
a.out
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
This will print an error because we haven't implemented the
|
|
Packit |
3adb1e |
StrToUpper function correctly. We are just returning the string
|
|
Packit |
3adb1e |
without changing it to upper case.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
char* StrToUpper(char* str) {
|
|
Packit |
3adb1e |
return str;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Rewrite this as follows:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
char* StrToUpper(char* str) {
|
|
Packit |
3adb1e |
char* p;
|
|
Packit |
3adb1e |
for (p = str ; *p ; ++p) *p = toupper(*p);
|
|
Packit |
3adb1e |
return str;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Recompile and run the tests again. The test should pass this
|
|
Packit |
3adb1e |
time.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
WHAT TO DO NEXT
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
At this point you might want to write more tests for the
|
|
Packit |
3adb1e |
StrToUpper function. Here are some ideas:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
TestStrToUpper_EmptyString : pass in ""
|
|
Packit |
3adb1e |
TestStrToUpper_UpperCase : pass in "HELLO WORLD"
|
|
Packit |
3adb1e |
TestStrToUpper_MixedCase : pass in "HELLO world"
|
|
Packit |
3adb1e |
TestStrToUpper_Numbers : pass in "1234 hello"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
As you write each one of these tests add it to StrUtilGetSuite
|
|
Packit |
3adb1e |
function. If you don't the tests won't be run. Later as you write
|
|
Packit |
3adb1e |
other functions and write tests for them be sure to include those
|
|
Packit |
3adb1e |
in StrUtilGetSuite also. The StrUtilGetSuite function should
|
|
Packit |
3adb1e |
include all the tests in StrUtil.c
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Over time you will create another file called FunkyStuff.c
|
|
Packit |
3adb1e |
containing other functions unrelated to StrUtil. Follow the same
|
|
Packit |
3adb1e |
pattern. Create a FunkyStuffGetSuite function in FunkyStuff.c.
|
|
Packit |
3adb1e |
And add FunkyStuffGetSuite to AllTests.c.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
The framework is designed in the way it is so that it is easy to
|
|
Packit |
3adb1e |
organize a lot of tests.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
THE BIG PICTURE
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Each individual test corresponds to a CuTest. These are grouped
|
|
Packit |
3adb1e |
to form a CuSuite. CuSuites can hold CuTests or other CuSuites.
|
|
Packit |
3adb1e |
AllTests.c collects all the CuSuites in the program into a single
|
|
Packit |
3adb1e |
CuSuite which it then runs as a single CuSuite.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
The project is open source so feel free to take a peek under the
|
|
Packit |
3adb1e |
hood at the CuTest.c file to see how it works. CuTestTest.c
|
|
Packit |
3adb1e |
contains tests for CuTest.c. So CuTest tests itself.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Since AllTests.c has a main() you will need to exclude this when
|
|
Packit |
3adb1e |
you are building your product. Here is a nicer way to do this if
|
|
Packit |
3adb1e |
you want to avoid messing with multiple builds. Remove the main()
|
|
Packit |
3adb1e |
in AllTests.c. Note that it just calls RunAllTests(). Instead
|
|
Packit |
3adb1e |
we'll call this directly from the main program.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Now in the main() of the actual program check to see if the
|
|
Packit |
3adb1e |
command line option "--test" was passed. If it was then I call
|
|
Packit |
3adb1e |
RunAllTests() from AllTests.c. Otherwise run the real program.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
Shipping the tests with the code can be useful. If you customers
|
|
Packit |
3adb1e |
complain about a problem you can ask them to run the unit tests
|
|
Packit |
3adb1e |
and send you the output. This can help you to quickly isolate the
|
|
Packit |
3adb1e |
piece of your system that is malfunctioning in the customer's
|
|
Packit |
3adb1e |
environment.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CuTest offers a rich set of CuAssert functions. Here is a list:
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
void CuAssert(CuTest* tc, char* message, int condition);
|
|
Packit |
3adb1e |
void CuAssertTrue(CuTest* tc, int condition);
|
|
Packit |
3adb1e |
void CuAssertStrEquals(CuTest* tc, char* expected, char* actual);
|
|
Packit |
3adb1e |
void CuAssertIntEquals(CuTest* tc, int expected, int actual);
|
|
Packit |
3adb1e |
void CuAssertPtrEquals(CuTest* tc, void* expected, void* actual);
|
|
Packit |
3adb1e |
void CuAssertPtrNotNull(CuTest* tc, void* pointer);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
The project is open source and so you can add other more powerful
|
|
Packit |
3adb1e |
asserts to make your tests easier to write and more concise.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
AUTOMATING TEST SUITE GENERATION
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
make-tests.sh will grep through all the .c files in the current
|
|
Packit |
3adb1e |
directory and generate the code to run all the tests contained in
|
|
Packit |
3adb1e |
them. Using this script you don't have to worry about writing
|
|
Packit |
3adb1e |
AllTests.c or dealing with any of the other suite code.
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
CREDITS
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
[02.23.2003] Dave Glowacki has added
|
|
Packit |
3adb1e |
(1) file name and line numbers to the error messages, (2)
|
|
Packit |
3adb1e |
AssertDblEquals for doubles, (3) Assert<X>Equals_Msg version of
|
|
Packit |
3adb1e |
all the Assert<X>Equals to pass in optional message which is
|
|
Packit |
3adb1e |
printed out on assert failure.
|