MiniCppUnit是一个轻量级的CppUnit,可以用来做C++代码的单元测试。
MiniCppUnit一种两个核心文件:MiniCppUnit.hxx和MiniCppUnit.cxx
在其压缩包内,还有一个TestRunner.cxx文件,这里面有一个简单的main函数,如果用户要测试的代码片段没有主函数,则可以使用此文件。
此文件就一行代码:
return TestFixtureFactory::theInstance().runTests() ? 0 : -1;
TestFixtureFactory本身是一个单例,它内部有一个TestFixture的Creator列表:
std::list<FixtureCreator> _creators;
FixtureCreator其实是一个函数指针类型,它指向的是一个个创建TestFixture的函数的地址
TestFixtureFactory的runTests()函数会遍历_creators中的每一个FixtureCreator函数指针,用它创建相应的TestFixture(返回的是其基类Test的指针类型),然后调用其runTest()接口。
TestFixture内部又有一个Test Case的列表:
typedef std::list<Test*> TestCases;
TestCases _testCases;
TestFixture的runTest()函数会遍历_testCases中的每一个Test Case,并调用每个Test Case的runTest()接口。在调用每个Test Case的runTest()接口前后,分别会调用TestFixture的setUp()和tearDown()函数,这两个是虚函数,可以重载。
基本的调用流程已经分析清楚了,现在有两个问题:
1)TestFixture的Creator是如何添加到TestFixtureFactory的_creators列表中的?
2)每一个Test Case是如何添加到TestFixture的_testCases列表中的?
要回答这两个问题,先看一下它给一个一个使用的例子UsageExample.cxx
#include "MiniCppUnit.hxx"
class MyTestsExample : public TestFixture<MyTestsExample>
{
public:
TEST_FIXTURE( MyTestsExample )
{
TEST_CASE( testAssert );
TEST_CASE( testAssertMessage );
TEST_CASE( testAdditionInts );
TEST_CASE( testDoubles );
TEST_CASE( testFloats );
TEST_CASE( testLongDoubles );
TEST_CASE( testNotANumber );
TEST_CASE( testComparisonWithEpsilon );
TEST_CASE( testException );
TEST_CASE( testStringAddition );
}
void testAssert()
{
ASSERT(3==1+2);
}
void testAssertMessage()
{
ASSERT_MESSAGE( 2==1+1, "2 should be 1 plus 1 ");
}
void testAdditionInts()
{
ASSERT_EQUALS( 2, 1+1 );
}
void testDoubles()
{
double expected = 10.00002;
double result = 10.00001;
ASSERT_EQUALS(expected, result);
// Notice that minicppunit uses an scaled epsilon
// that depends on the expected value.
// So, the previous assert passes but the following,
// if descomented, should fail!
double expected2 = 0.00002;
double result2 = 0.00001;
//ASSERT_EQUALS(expected2, result2);
}
void testFloats()
{
float expected = 0.000002;
float result = 0.000001;
ASSERT_EQUALS(expected, result);
}
void testLongDoubles()
{
long double expected = 0.000002;
long double result = 0.000001;
ASSERT_EQUALS(expected, result);
}
void testNotANumber()
{
double expected = 0.0/0.0;
double result = 0.0/0.0;
ASSERT_EQUALS(expected, result);
}
void testComparisonWithEpsilon()
{
long double expected = 0.02;
long double result = 0.01;
ASSERT_EQUALS_EPSILON(expected, result, 0.05);
}
void testException()
{
try
{
someCodeThatShouldThrowException();
FAIL( "Should have rised an exception" );
} catch (std::exception & e)
{
// maybe assert for string in e.what()
}
}
void testStringAddition()
{
std::string result("Hello");
result += " World";
ASSERT_EQUALS("Hello World", result);
}
private:
void someCodeThatShouldThrowException()
{
throw std::exception();
}
};
REGISTER_FIXTURE( MyTestsExample );
由此可见,在静态变量estaticMyTestsExample构造时,会将CreadorMyTestsExample加入到TestFixtureFactory的creator列表中。这就回答了第一个问题。
第二个问题就更简单了,将下列代码完成了Test Case的注册工作:
TEST_CASE( testAssert );
TEST_CASE( testAssertMessage );
TEST_CASE( testAdditionInts );
TEST_CASE( testDoubles );
TEST_CASE( testFloats );
TEST_CASE( testLongDoubles );
TEST_CASE( testNotANumber );
TEST_CASE( testComparisonWithEpsilon );
TEST_CASE( testException );
TEST_CASE( testStringAddition );