CppUnit学习笔记

CPPUnit是由JUnit转化而来的一种C++程序测试框架,最初的作者是Michael Feathers
CodeUnitTestFirst is not a testing technique, it's a design technique.

先要了解一下JUnit/xUnit框架的实现思想
典型的单元测试可以描述为:
确保方法接受预期范围内的输入,并且对每个测试输入返回预期的结果

单元测试 :单元测试测的是独立的一个工作单元。在Java应用程序中,独立的一个工作单元常常指的是一个方法(但并不总是如此)。作为对比,集成测试和接收测试则检查多个组件如何交互。一个工作单元是一项任务,它不依赖于其他任何任务的完成。

单元测试所关注的常常是方法是否满足API契约。就如同人们同意在某种条件下交换特定的货物或者服务所写下的契约,API契约被看作是方法接口的正式协定。方法要求调用者提供特定的值或对象,并(作为交换)会返回特定的值或对象。如果契约不能满足,那么方法就抛出异常来表明契约没有被遵守。如果一个方法的行为同预期不符,那么我们说这个方法破坏了契约。

API契约:对应用编程接口(API)的一种看法,把它看作是调用者和被调用者之间的正式协定。单元测试常常可以通过证实期待的结果来帮助定义API契约。API契约的说法来自伴随Eiffel编程语言而流行的Design by Contract实践(http://archive.eiffel.com/doc/manuals/technology/contract)。

哪些内容值得测试Right-BICEP
Right--Are the results right? 结果是否正确
B--Are all the boundary conditions CORRECT? 所有边界条件是否正确
I--Can you check inverse relationships? 是否检查了反向关系
C--Can you cross-check results using other means? 交叉检查结果是否正确.(换种算法来检查结果是否一致)E--Can you force error conditions to happen? 强制错误条件出现时结果是否正确
P--Are performance characteristics within bounds? 是否满足性能要求

CORRECT边界条件
C--Conformance: Does the value conform to an expected format?
O--Ordering:Is the set of values ordered or unordered as appropriate?
R--Range:Is the value within reasonable minimum and maximum values?
R--Reference: Does the code reference anything external that isn't under direct control of the code itself?
E--Existence:Does the value exist (e.g., is non-null, nonzero,present in a set, etc.)?
C--Cardinality: Are there exactly enough values?
T--Time (absolute and relative): Is everything happening in order? At the right time? In time?

一般来说,下面的情形往往容易发生bug
--Totally bogus or inconsistent input values, such as a file name of "!*W:Xn&Gi/w>g/h#WQ@".
--Badly formatted data, such as an e-mail address without a top-level domain ("fred@foobar.").
--Empty or missing values (such as 0, 0:0, "", or null).
--Values far in excess of reasonable expectations, such as a person's age of 10,000 years.
--Duplicates in lists that shouldn't have duplicates.
--Ordered lists that aren't, and vice-versa. Try handing a pre-sorted list to a sort algorithm, for instance--or even a reverse-sorted list.
--Things that arrive out of order, or happen out of expected order, such as trying to print a document before logging in, for instance.

--Useful Links:
http://sourceforge.net/projects/cppunit/
http://cppunit.sourceforge.net/cppunit-wiki/FrontPage
http://www.junit.org/
http://www.mockobjects.com/

--Installation on Linux
1. Download cppunit-1.10.2 package from cppunit site and extract it
 http://cppunit.sourceforge.net

2. Download autoconf 2.2.4
http://ftp.man.poznan.pl/pub/gnu/gnu/autoconf/

3. Install autoconf
./configure
./make
./make install

4. Install cppunit
./configure CXX=/usr/bin/g++296 CXXFLAGS=-O2
./make
./make install
./make clean

5. Verify installation
ls /usr/local/lib/libcppunit*

--Installation on Windows
(summarized by hongshengyi)
1. 编译cppunit目录/src/cppunit/CppUnitLibraries.dsw中的cppunit_dll项目,release版生成cppunit_dll.lib和cppunit_dll.dll,debug版生成cppunitd_dll.lib和cppunitd_dll.dll。这是CPPUnit基本类库。

2.  编译cppunit目录/src/cppunit/CppUnitLibraries.dsw中的TestRunner项目。release版生成TestRunner.lib和TestRunner.dll,debug版生成TestRunnerd.lib和TestRunnerd.dll。这是使用MFC的图形化界面的类库。

3.  把所有lib文件放置到CommonFiles/Lib目录下面。
或者 在VC中工具-》选择-》目录-》Library Files中将cppunit中的lib目录放进来

4. 把dll文件放到相应的debug和release可执行目录下面。

5. 在VC中工具-》选择-》目录-》Include Files中将cppunit中的include目录放进来

6.vc中工程-》设置-》link 放入cppunitd_dll.lib
在Projects/Settings.../C++/C++ Language页选中Enable RTTI。
在Projects/Settings.../C++/Code Generation页选择Use run-time library中的内容:
Release版, 选择"Mulithreaded DLL".
Debug版, 选择 "Debug Multihreaded DLL".

7.可以引入宏AddingUnitTestMethod.dsm,可以方便生成测试框架

8.写完待测试和测试类后,还要写个main函数

--Example
----------------------Hello world of Cpp unit------------------
(http://pantras.free.fr/articles/helloworld.html)

#include

#include
#include
#include
#include
#include
#include

class Test : public CPPUNIT_NS::TestCase
{
  CPPUNIT_TEST_SUITE(Test);
  CPPUNIT_TEST(testHelloWorld);
  CPPUNIT_TEST_SUITE_END();

public:
  void setUp(void) {}
  void tearDown(void) {}

protected:
  void testHelloWorld(void) { std::cout << "Hello, world!" << std::endl; }
};

CPPUNIT_TEST_SUITE_REGISTRATION(Test);

int main( int argc, char **argv )
{
  // Create the event manager and test controller
  CPPUNIT_NS::TestResult controller;

  // Add a listener that colllects test result
  CPPUNIT_NS::TestResultCollector result;
  controller.addListener( &result );       

  // Add a listener that print dots as test run.
  CPPUNIT_NS::BriefTestProgressListener progress;
  controller.addListener( &progress );     

  // Add the top suite to the test runner
  CPPUNIT_NS::TestRunner runner;
  runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
  runner.run( controller );

  return result.wasSuccessful() ? 0 : 1;
}
Complie:
/usr/bin/g++296 -O2 -g -o helloworld helloworld.cpp /
-I. -I./h -I/usr/include -I/usr/local/include /
-L/usr/lib -L/usr/local/lib -ldl -lm -lpthread -lcppunit


--Key points:
1.先写测试代码,然后编写符合测试的代码。至少做到完成部分代码后,完成对应的测试代码;
2.测试代码不需要覆盖所有的细节,但应该对所有主要的功能和可能出错的地方有相应的测试用例;
3.发现 bug,首先编写对应的测试用例,然后进行调试;
4.不断总结出现 bug 的原因,对其他代码编写相应测试用例;
5.每次编写完成代码,运行所有以前的测试用例,验证对以前代码影响,把这种影响尽早消除;
6.不断维护测试代码,保证代码变动后通过所有测试;

--Main steps
1. Initialize test fixture
2. Initialize testcase : setUp
3. Execute test case: assert
4. Release testcase: tearDown
5. Release test fixture

提供的断言:
CPPUNIT_ASSERT(condition) // 确信condition为真
CPPUNIT_ASSERT_MESSAGE(message, condition) // 当condition为假时失败, 并打印message
CPPUNIT_FAIL(message) // 当前测试失败, 并打印message
CPPUNIT_ASSERT_EQUAL(expected, actual) // 确信两者相等
CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) // 失败的同时打印message
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) // 当expected和actual之间差大于delta时失败

运行方式:
CpUnit::TextUi::TestRunner // 文本方式的TestRunner
CppUnit::QtUi::TestRunner // QT方式的TestRunner
CppUnit::MfcUi::TestRunner // MFC方式的TestRunner

 

(Thanks liqun and hongshengyi's article)

你可能感兴趣的:(Programming)