Update (20090515): James Grenning modestly pointed out that he is in fact the co-author of CppUTest, along with Bas Vodde and Michael Feathers. My apologies to Bas and Michael.
Yesterday I lamented, via Twitter, my failure at getting CppUTest built and running easily on OSX. Fortunately for me, James Grenning (the author of CppUTest) saw my distress signal and responded with some very helpful advice about using more of the shell scripts that come bundled with CppUTest to setup a new project and get started quickly.
James suggested I try the NewProject and NewClass scripts, which I did:
NewProject takes a single argument: the name of the project to create. The script creates the following directory structure (in pwd). I ran the script like so:
$> NewProject MyProject
And ended up with a directory structure like this:
MyProject
|-- Makefile
|-- include
| |-- MyProject
| | `-- MyProjectBuildTime.h
|-- lib
|-- src
| |-- MyProject
| | `-- MyProjectBuildTime.cpp
`-- tests
|-- AllTests.cpp
|-- MyProject
| |-- MyProjectBuildTimeTest.cpp
`-- MyProjectNeedsTests.cpp
This is nice. Now we can add some tests to the ./tests/MyProjectNeedsTests.cpp file and they will be run as part of our build. In fact, if you open that file, you’ll see a purposely failing test (using the FAIL test macro) that will give us a starting point to begin test driving our design. The Red stage of Red, Green, Refactor.
You may want to build the project at this point, just to see the test failing. It makes it all the sweeter when you subsequently make it fail. Remember: Depending on where you created the new project, you might need to modify your project’s Makefile to ensure that the CPP_U_TEST path variable points to the CppUTest installation directory.
James’ next tip was to add files for a new Class to the project. This is essential if you’re going to do any useful TDD, which goes hand in hand with OO.
NewClass takes a couple of arguments:
- ClassName this will be the name of your new class and associated header and source files
- Directory this tells the script where in your project directory structure the source files for ClassName should be placed. If you want to create consistent package directories in your project, use the NewPackageDirs script.
- Note The NewPackageDirs script is not included in the v1.00 zip file release of CppUTest but you can get it from the CppUTest SVN repository at sourceforce.
Note: The script won’t create a directory for your new class files if it doesn’t already exist, so mkdir the relevant directory in your project root manually (I’m modifying the script and submitting a patch for this as we speak)
First, using James’ example, I create a consistent set of package directories in my project with the NewPackageDirs script, like this:
$> NewPackageDirs util
Then, I create a new set of files for a MyClass class, in the util package directory using the following command:
$> NewClass MyClass util
The structure of the MyProject directory tree should now look like this:
.
|-- Makefile
|-- include
| |-- MyProject
| | `-- MyProjectBuildTime.h
| `-- util
| `-- MyClass.h
|-- lib
|-- src
| |-- MyProject
| | `-- MyProjectBuildTime.cpp
| `-- util
| `-- MyClass.cpp
`-- tests
|-- AllTests.cpp
|-- MyProject
| |-- MyProjectBuildTimeTest.cpp
| `-- MyProjectNeedsTests.cpp
`-- util
`-- MyClassTest.cpp
Notice that we now have header, implementation and test files for MyClass.
Note: If you added new package directories to your project tree, then remember to edit the project’s Makefile to have them built. I used the following to add the util package:
...
SRC_DIRS = \
src/MyProject \
src/util
...
TEST_SRC_DIRS = \
tests \
tests/MyProject \
tests/util \
...
INCLUDES =\
-I.\
-Iinclude/MyProject\
-Iinclude/util\
-I$(CPPUTEST_HOME)/include/\
-I$(CPPUTEST_HOME)/include/Platforms/$(CPP_PLATFORM)\
...
Next we build the solution and watch some tests fail.
Note for OSX users: If you’re a user of the excellent iTerm terminal application then beware! iTerm sets the COMMAND_MODE environment variable to legacy, which will cause the archive section of the build to fail, because ar won’t call ranlib to build the table of contents on your archive files. phew. Workaround this problem by setting the COMMAND_MODE environment variable to unix2003 or simply do your building from the built-in Terminal.app application.
I run the build from inside the MyProject/ directory as follows:
$> make all
Here’s the output, with some of the dull build bits trimmed out:
compiling AllTests.cpp
...
Building archive lib/libMyProject.a
...
Linking MyProject_tests
Running MyProject_tests
tests/MyProject/MyProjectNeedsTests.cpp:15: error:
Failure in TEST(MyProjectNeedsTests, Create)
MyProject needs some tests
..
Errors (1 failures, 2 tests, 2 ran, 1 checks, 0 ignored, 0 filtered out, 3 ms)
make: *** [all] Error 1
Success! The red bar (use your imagination) indicates a failing test. Now I’m ready to start getting into some TDD with C++, by adding some tests!
My thanks to James Grenning for his timely tweets.