我不知道你们如何在编写每行代码时进行不同级别的测试:单元测试,集成测试等。
举个例子,如果你想对刚刚编写的函数进行单元测试,你会写另一个完整的主函数和 Makefile 进行测试吗?或者你会修改项目的主函数来测试该函数吗?还是你只是在调试模式下运行项目,在函数被调用之前停止并修改其参数的值?
我相信一定有一些方便而常见的方法大多数人都在使用,只有我不知道而已。
•创建单元测试和测试套件的方便程度。CppUnit和CppTest都可以创建类方法的单元测试,其中类本身派生自某个工具提供的Test类。CppTest的语法略微简单,测试注册发生在类构造函数内部。对于CppUnit,需要额外的宏CPPUNIT_TEST_SUITE和CPPUNIT_TEST_SUITE_ENDS。
•运行测试。CppTest只需在测试套件上调用run方法,而CppUnit使用一个名为TestRunner的单独类,其run方法被调用以运行测试。
•扩展测试层次结构。对于CppTest,始终可以通过创建从旧类继承的新类来扩展先前的测试套件。新类将定义一些添加到单元测试池中的附加函数。只需在新类类型的对象上调用run方法即可。相比之下,CppUnit要求您使用宏CPPUNIT_TEST_SUB_SUITE以及类继承来实现相同的效果。
•生成格式化输出。CppTest和CppUnit都具有自定义输出的能力。但是,虽然CppTest具有有用的预定义HTML输出格式化程序,但CppUnit没有。但是,CppUnit专门支持XML格式。两者都支持文本和编译器样式格式。
•创建测试固件。要使用测试固件,CppUnit要求测试类派生自CppUnit :: TestFixture。您必须为设置和拆卸例程提供定义。对于CppTest,您只需要为设置和拆卸例程提供定义。这绝对是更好的解决方案,因为它使客户端代码简单化。•预定义实用程序宏支持。CppTest和CppUnit都具有可比较的宏集,用于断言、处理浮点数等。
•头文件。CppTest要求您包含单个头文件,而CppUnit客户端代码必须包含多个头文件,例如HelperMacros.h和TextTestRunner.h,具体取决于所使用的功能。
http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-
CPPTEST
#include “cppTest.h”
class myTestWithFixtures : public Test::Suite {
void function1_to_test_some_code( );
void function2_to_test_some_code( );
public:
myTestWithFixtures ( ) {
TEST_ADD (function1_to_test_some_code) {...};
TEST_ADD (function2_to_test_some_code) {...};
}
protected:
virtual void setup( ) { ... };
virtual void tear_down( ) { ... };
};
int main ( )
{
myTestWithFixtures tests;
Test::TextOutput output(Test::TextOutput::Verbose);
return tests.run(output);
}
http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-
CPPUNIT
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
class mystringTest : public CppUnit::TestFixture {
public:
void setUp() { ... };
void tearDown() { ... };
void function1_to_test_some_code() { ... };
void function2_to_test_some_code() { ... };
CPPUNIT_TEST_SUITE( mystringTest );
CPPUNIT_TEST( function1_to_test_some_code );
CPPUNIT_TEST( function2_to_test_some_code );
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION( mystringTest );
int main ()
{
CppUnit::TestSuite* suite = new CppUnit::TestSuite("mystringTest");
suite->addTest(new CppUnit::TestCaller<mystringTest>("checkLength",
&mystringTest::checkLength));
suite->addTest(new CppUnit::TestCaller<mystringTest>("checkValue",
&mystringTest::checkLength));
// client code follows next
CppUnit::TextTestRunner runner;
runner.addTest(suite);
runner.run();
return 0;
}
http://www.ibm.com/developerworks/aix/library/au-ctools2_cppunit/
Boost单元测试框架
该文章介绍了Boost单元测试框架,它是一个C++单元测试框架,可以帮助开发人员编写和运行测试用例。使用这个框架可以快速、简便地测试代码,并且输出结果易于理解。#include <boost/test/unit_test.hpp>
using namespace std;
struct CMyFooTestFixture
{
CMyFooTestFixture() { ... } //SetUp
~CMyFooTestFixture() { ... } //TearDown
void function1_to_test_some_code(CMyFoo& foo) { ... };
void function2_to_test_some_code(CMyFoo& foo) { ... };
}
BOOST_FIXTURE_TEST_SUITE(MyFooTest, CMyFooTestFixture);
BOOST_AUTO_TEST_CASE(function1_to_test_some_code)
{
CMyFoo foo;
function1_to_test_some_code(foo);
}
BOOST_AUTO_TEST_CASE(function1_to_test_some_code2)
{
CMyFoo foo;
function1_to_test_some_code(foo);
}
BOOST_AUTO_TEST_SUITE_END();
xUnit是一个单元测试模块家族。x被替换为所使用框架语言的字母。该家族目前包括:
我曾经在使用CppUnit的项目中取得了良好的结果。最近,我尝试将其集成到自动构建环境中(例如Hudson),但遇到了许多障碍。
理想情况下,构建应自动构建并运行单元测试。在这种情况下,代码从测试环境运行(因此具有自己的主循环)。在我的案例中,另一个复杂性是我使用嵌入式系统;printf并不总是可行的。如果您在PC上运行,CUnit和CppUnit可以帮助您实现良好的单元测试。请查看如何使用结果;持续集成系统将大大提高您的效率。
另一个值得一看的框架是Maestra。它依赖于C99(Microsoft从未实现过,但对于gcc来说非常好!)
我通常采用以下方式:
int foo(int bar) {
...
}
#ifdef FOO_UNITTEST
int main(int argc, char *argv[]) {
// tests
}
#endif
我有一个makefile,其中CFLAGS
中包含-DFOO_UNITTEST
。
这虽然有些笨拙,但你总是可以将测试代码放在代码旁边。
我喜欢UnitTest++。它非常容易设置,编写测试比典型的CppUnit更容易。每个测试的编码开销非常小,因此您更有可能编写它们!
至于我测试什么,我倾向于测试类的公共接口,但如果我只是进行一些重构并将其拆分为较小的函数,则不会为每个函数编写一组测试 - 它们应该由测试公共接口的测试覆盖。只要公共接口根据测试工作正常,世界上就一切安好。