今天是五一劳动节,为了不为全国人民添堵,本人还是决定宅在家里学点东西。
C++里的单元测试工具我接触过的有boost_unit,gtest。
本人深知单元测试的重要性与TDD(测试驱动开发)的思想。所以,测试工具对我而言开发利器。我们必须要掌握其中的一门。
听说CppUnit的兼容性比较好,于是博主就颇有兴趣地学习了一下CppUnit的使用。
网上的资料很多,已有很多牛人已做了分享。
CppUnit入门,CppUnit百科,CppUnit使用详解,等等。在百度上搜“CppUnit”,有很多资料。
本人参照上面的示例自己尝试做了一遍。
安装
首先是安装cppunit。本人的系统是CentOS,就直接用yum安装使是。
1 |
|
也可以选择下载源码安装。步骤大致都是:解压缩,./configure,make,sudo make install。
安装完成之后,在 /usr/include 路径下会多一个 cppunit 目录,这就是cppunit的头文件所在处。在 /usr/lib/ 路径下有 libcppunit-1.12.so.1 libcppunit-1.12.so.1.0.0 libcppunit.so 3个文件。
我们在链接的时候,一定要记得加 -lcppunit 项。
Lession-1
编辑文件:MathTest.h
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
class MathTest : public CppUnit::TestFixture
{
protected:
int m_value1, m_value2;
public:
MathTest() {}
void setUp () {
m_value1 = 2;
m_value2 = 3;
}
void testAdd() {
int result = m_value1 + m_value2;
CPPUNIT_ASSERT(result == 5);
}
void testSub() {
int result = m_value1 - m_value2;
CPPUNIT_ASSERT(result == 0);
}
};
编译文件:TestMain.cpp
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestSuite.h>
#include <cppunit/TestCaller.h>
#include "MathTest.h"
int main(int argc, char **argv)
{
CppUnit::TextUi::TestRunner runner;
CppUnit::TestSuite *suite = new CppUnit::TestSuite();
suite->addTest(new CppUnit::TestCaller<MathTest>\
("testAdd", &MathTest::testAdd));
suite->addTest(new CppUnit::TestCaller<MathTest>\
("testSub", &MathTest::testSub));
runner.addTest(suite);
runner.run("", true);
return 0;
}
编译命令:
$ g++ -o test TestMain.cpp -lcppunit
执行结果:
[hevake_lcj@localhost Lession1]$ ./test
..F
!!!FAILURES!!!
Test Results:
Run: 2 Failures: 1 Errors: 0
1) test: testSub (F) line: 21 MathTest.h
assertion failed
- Expression: result == 0
<RETURN> to continue
总结:
在这个例程中,我们自定义了 CppUnit::TestFixture 子类 MathTest 。在MathTest可选择性地定义 setUp() 与 tearDown()
还需要手动将其加入到 TestSuite对象中去。将 TestSuite对象加入到TestRunner中才能进行测试。
要添加一个测试,需要改TestMain.cpp文件。这样的测试框架不易维护。
Lession-2
CppUnit 一定考虑到了Lession-1的问题,并提供了许多宏定义,使我们的测试代码更可读。如下是示例:
编辑文件:DemoTest.h
#ifndef __DEMO_TEST_H__
#define __DEMO_TEST_H__
#include <cppunit/extensions/HelperMacros.h>
class DemoTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(DemoTest);
CPPUNIT_TEST(testFunc);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void testFunc();
};
#endif //__DEMO_TEST_H__
编辑文件:DemoTest.cpp
#include "DemoTest.h"
#include <iostream>
#include <cppunit/extensions/HelperMacros.h>
using namespace std;
CPPUNIT_TEST_SUITE_REGISTRATION(DemoTest);
void DemoTest::setUp()
{
cout << "DemoTest::setUp()" << endl;
}
void DemoTest::tearDown()
{
cout << "DemoTest::tearDown()" << endl;
}
void DemoTest::testFunc()
{
cout << "DemoTest::testFunc()" << endl;
CPPUNIT_ASSERT(12 == 11+1);
}
编辑文件:TestMain.cpp
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
int main(int argc, char **argv)
{
CppUnit::TextUi::TestRunner runner;
CppUnit::TestFactoryRegistry istry = \
CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
runner.run();
return 0;
}
编译命令:
$ g++ -o test DemoTest.cpp TestMain.cpp -lcppunit
执行结果:
[hevake_lcj@localhost Lession2]$ ./test
.DemoTest::setUp()
DemoTest::testFunc()
DemoTest::tearDown()
OK (1 tests)
总结:
我想,其大概的原理就是在 CPPUNIT_TEST_SUITE_REGISTRATION(TestDemo) 宏中就定义了一个全局的 TestDemo 对象,在该 TestDemo 的构造函数中 将自己添加到了 单例 CppUnit::TestFactoryRegistry 中。所以在 main() 函数中调用 CppUnit::TestFactoryRegistry::getRegistry() 时就可以获得所有我们自己定义的 CppUnit::TestFixture 子类。