There are many tools for testing, and there are different kinds of testing at different granularities, for different phases of the development cycle.
For tests of the largest granularity, such as acceptance tests, the tools and methods are usually language neutral. For example, you can test a Ruby web application using webrat or watir, and you can use the same set of tools to test a C++ web server. In this section, I’m just going to focus on small tests, in particular, tests of individual methods and classes.
There are a number of test frameworks for C++. Boost has a test library, Qt has a unit test library, and Google also open-sourced its C++ testing framework. There are a few others. You could write tests without any of them, but the tools help to reduce repetition and make tests more concise. In my experience this is quite important, because the easier it is to write tests, the more motivated I am to write them.
The testing frameworks all use similar terminology. Usually a test source file contains one or more test cases, and a test case contains one or more tests. It’s customary to write one test case for each class, and one or more tests for each public method. Most of those tools are similar, and it doesn’t really matter which one you use. I like Google’s framework because it’s the least verbose and it’s also what I use at work. Here’s a quick example of one test in a test case for an RSS feed parser:
class FeedParserTest: public ::testing::Test {
protected:
void SetUp() {
feed_.reset(new Feed);
}
RssFeedParser parser_;
shared_ptr<Feed> feed_;
};
TEST_F(FeedParserTest, ParseSlashdot) {
QFile rss(TEST_DATA_DIR "/slashdot.rss");
ASSERT_TRUE(rss.exists());
rss.open(QIODevice::ReadOnly);
parser_.startNewFeed(feed_);
while (rss.bytesAvailable() > 0) {
parser_.append(rss.read(CHUNK_SIZE));
}
EXPECT_TRUE(parser_.finished());
EXPECT_EQ("Slashdot", parser_.feed()->title());
EXPECT_EQ("http://slashdot.org/", parser_.feed()->site_url());
}
Each test class inherit from testing::Test, and there are two virtual functions you could override to set up and tear down your test fixture. void SetUp() and void TearDown() are called before and after each test respectively. You can also define two static class functions static void SetUpTestCase() and static void TearDown() which are called before and after all tests in the test case respectively. In other words, they are only called once for the test case. Ideally, you should implement the test fixture in SetUp() and TearDown(), because you don’t want to introduce dependencies between the tests. For example, you don’t want to be in a situation where just rearranging the order of tests would break them. SetUpTestCase() and TearDownTestCase() are mainly used for expensive initialization such as reading large amounts of data from disk, which you don’t want to do for every single test.
The TEST_F() macro defines a test with fixture, which has access to the test class defined earlier. There is also a TEST() macro that defines a test without fixture which is essentially just a simple function. The framework provides two families of assertions that you can use in tests. The ASSERT_* family of assertions immediately abort the current test if the expected condition is not true. They are usually used when it doesn’t make sense to continue the test, for example, where there is a NULL pointer that you need to dereference later, or some critical data is missing. The EXPECT_* family of assertions cause the test fail if the condition does not hold, but they allow the test to continue, so that you can find all failing expectations in one run.
There is no need to write a main() function. The testing framework provides a standard main() that you can link with, which runs all all defined tests. The resulting test executable has a few command line options that you can use to filter tests or change output formats. Just run your test executable with the --help flag to see all available options.
(To be continued …)

