CPPUNIT COOKBOOK Chinese version
2003-6-30 Wei network power
This is my first complete translation article. Welcome everyone, contact me: zgump@sina.com ******************************************************* *************************** This article is a simple entry guidance to help you quickly get started . Simple Test Case You want to know if your code is working. what should you do? There are many ways. Use the debugger to debug or lose some stream output instructions in your code is two simple methods, but they have their own shortcomings. Direct debugging code is a good idea, but it is not automatic. You have to re-debug after each change code. The output stream text is also good, but it makes the code face, and in most cases, the information it output is more than what you want. Testing in CPPUnit can be made automatically. These tests can be easily established, and once you are writing, they can help you understand the quality of your code. In order to make a simple test, this is what you have to do: a class is derived from TestClass. Override runtest () method. When you want to check a value, call CPPUNIT_ASSERT (BOOL) if the test success this Assert expression can be passed successfully. For example, in order to test a complex comparison, writing as follows: Class ComplexNumbertest: Public cppunit :: testcase {public: complexNumbertest (std :: string name): cppunit :: testcase () {} void runtest () {cppunit_assert (Complex (10, 1) == Complex (10, 1)); CPPUnit_assert (! (COMPLEX (1, 1) == Complex (2, 2)));}}; this is a simple test. In general, you will have a lot of small test cases, and I hope to test in the same object collection. In order to achieve this, use FixTure. FixTure is a set of objects that are used as the basis for testing a set of use cases. When you are testing while testing, it is very convenient to use FixTure. Then we try this development method while learning the method of use of FixTure. Assuming that we want to develop a plural class, we start with the empty class named Complex. Class Complex {}; now established the above ComplexNumbertest test case, compiling them to see what will happen. The first thing we noticed is to have some compilation errors. The test uses the operator ==, but it is not defined. Modified as follows: BOOL Operator == (Const Complex & A, Const Complex & B) {Return True;} Now compile and run. This compilation passed, but did not pass the test.
We need to write some code to make the operator == can work correctly, so we change the code again: Class Complex {Friend Bool Operator == (Const Complex & A, Const Complex & B); Double Real, Imaginary; Public: Complex (Double R) Double I = 0): Real (r), Imaginary (i) {}}; Bool Operator == (Const Complex & A, Const Complex & B) {Return EQ (A.Real, B.REAL) && EQ (A. Imaginary, B.Imaginary;} If we compile and run, you can pass the test. Now we are ready to add some new operators and new test cases. It is convenient to use a fixture at this time. If we instantiate 3 to 4 multiple compacts and use them repeatedly in the test, it may be better. We do this: * Add a member variable for each part of FixTure. * Override setup () initializes these variables. * Override Teardown () Releases the resources you use in Setup (). class ComplexNumberTest: public CppUnit :: TestFixture {private: Complex * m_10_1, * m_1_1, * m_11_2; protected: void setUp () {m_10_1 = new Complex (10, 1); m_1_1 = new Complex (1, 1); m_11_2 = New Complex (11, 2);} void teardown () {delete m_10_1; delete m_1_1; delete m_11_2;}}; once we have this fixture, we can add operator , and other other operations during the development process symbol.
Test Case how to call a separate test in order to use a Fixture? Divided into two steps: * Write a test case in the FixTure class in the FixTure class * Create TestCaller to run the method here. He added some extra use case method Writing test class: private: complex * m_10_1, * M_1_1, * m_11_2; protected: void setup () {m_10_1 = new complex (10, 1); m_1_1 = new complex (1, 1); m_11_2 = new complex (11, 2);} void teardown () {delete m_10_1 ; delete m_1_1; delete m_11_2;} void testEquality () {CPPUNIT_ASSERT (* m_10_1 == * m_10_1); CPPUNIT_ASSERT ((* m_10_1 == * m_11_2)!);} void testAddition () {CPPUNIT_ASSERT (* m_10_1 * m_1_1 = = * m_11_2);}}; we can create and run an example below: CPPUnit :: TestCaller Test ("Testequality", & ComplexNumbertest :: Testequality); CPPUnit :: TestResult Result; Test .Run (& result); The second parameter of the constructor of the TestCaller is the address corresponding to Method in ComplexNumbertest. When this TestCaller runs, the specified Method will run. However, this approach also has no effect because it does not display diagnostic information. We can use Testrunner (hereinafter) to display this diagnostic information. Once we have several test cases, you can set them into a Suite. Suite What should you do in order to build multiple use cases and let them run all over? CPPUnit provides a TestSuite class to run any of them simultaneously. I have seen how to run a test case. In order to create a suite containing two or more cases, you should do so: CppUnit :: TestSuite suite; CppUnit :: TestResult result; suite.addTest (new CppUnit :: TestCaller ( "testEquality", & ComplexNumberTest :: testEquality ))); Suite.Addtest (New CPPUnit :: TestCaller ("Testaddition", & ComplexNumbertest :: TestAddition); TestSuites does not have to contain Caller with test cases. They can include Test interface Any object. For example: You can create a TestSuite in your code, I can also build one in my code, we can run simultaneously by establishing a TestSuite that contains them simultaneously.
CPPUnit :: TestSuite Suite; CPPUNIT :: TestResult Result; suite.addte (suite.addtest :: suite.run (& result); suite.run (& result); testrunner How do you run your Use the example and collect the test results? Once you have a TestSuite, you will want to run it. CPPUnit provides tools that define these Suite and display the results. You can join your Suite with Testrunner by adding a static Method in a TestSuite to make your Suite with Testrunner. For example, to see a TestRunner ComplexNumberTest suite, the code was added in the ComplexNumberTest: public: static CppUnit :: Test * suite () {CppUnit :: TestSuite * suiteOfTests = new CppUnit :: TestSuite ( "ComplexNumberTest"); suiteOfTests -> addTest (new CppUnit :: TestCaller ( "testEquality", & ComplexNumberTest :: testEquality)); suiteOfTests-> addTest (new CppUnit :: TestCaller ( "testAddition", & ComplexNumberTest :: testAddition)); return SuiteOftests;} In order to use this version, the following header is included in main.cpp: #include #include "esamplestcase.h" #include "complexnumbertest.h" and then in main () Adding AddTest (CPPUnit :: Test *): int Main (int Argc, char ** argv) {cppunit :: textui :: Testrunner Runner; runner.addtest (Exampletestcase :: suite ()); runner.addtest ComplexNumbertest :: Suite ()); runner.run (); return 0;} Testrunner runs these use cases. If all tests pass smoothly, you will get a feedback. If any test is not passed, you will get the following information: * The name of the failed test case * contains the name of this test source file * Errors occurred * Discover all the text in the CPPUnit_assert () call. Helper Macros You may have already noticed that static suite () in FixTure is a task to be done repeated and is easily erroneous.
We can use a set of macros with Test FixTure to automate these static Suite Method. Below is the code after using these macros, the code after class ComplexNumbertest: #include Class ComplexNumbertest: Public CPPUnit: : TestFixTure {First we declare this Suite, pass the name of this class to Macro: CPPUnit_Test_suite (ComplexNumbertest); This use of the static Suite () Method created by Suite to name it with a class name. Then we declare each test case: CPPUnit_test (Testequality); CPPUNIT_TEST (Testaddition); ); The remaining fixture remains non-moving: private: complex * m_10_1, * m_1_1, * m_11_2; protected: void setup () {m_10_1 = new complex (10, 1); m_1_1 = new complex (1, 1); m_11_2 = new Complex (11, 2);} void tearDown () {delete m_10_1; delete m_1_1; delete m_11_2;} void testEquality () {CPPUNIT_ASSERT (* m_10_1 == * m_10_1);! CPPUNIT_ASSERT ((* m_10_1 == * m_11_2 ));} void testaddition () {cppUnit_ASSERT (* m_10_1 * m_1_1 == * m_11_2);}}; add this Suite TestCaller name is the combination of this fixture name and Method name. For this use case, the name will be "ComplexNumbertest.Testequality" and "ComplexNumbertest.TestAddition". Helper Macros helps you write some commonly used assertions. E.g. Check if complexNumber will throw Mathexception exception when a number is zero: * Add this test example to the SUITE of CPPUNIT_TEST_EXCEPTION, specify the type of exception. * Test of writing this method CPPUNIT_TEST_SUITE (ComplexNumberTest); // [...] CPPUNIT_TEST_EXCEPTION (testDivideByZeroThrows, MathException); CPPUNIT_TEST_SUITE_END (); // [...] void testDivideByZeroThrows () {// The following line should throw a Mathexception. * M_10_1 / ComplexNumber (0);} If the expected exception is not thrown, this assertion will fail. TestFactoryRegistry TestFactoryRegistry is used to solve the following two defects: * Forgot to add your FixTure Suite to Test Runner (because it is in another file, it is easy to forget) * Because the compilation bottleneck caused by the addition of all test cases. TestFactoryRegistry is a place to register Suite when initialization.
To register with ComplexNumber Suite, add: #include cppunit_test_suite_registration (complexNumber); in fact, a static autoregistersuite type variable is declared. It will be registered with TestSuiteFactory to TestFactoryRegistry. TestSuiteFactory Returns the testsuite that ComplexNumber :: Suite () returned. In order to run these use cases, use text Test Runner, we don't have to include fixture: #include #include int main (int Argc, char ** argv) {CppUnit :: textUi :: TestRunner runner; TestFactoryRegistry the first instance we have: CppUnit :: TestFactoryRegistry ®istry = CppUnit :: TestFactoryRegistry :: getRegistry (); then we get and add a new TestSuite generated by TestFactoryRegistry, It contains all Test Suite.Runner.addTest (registration.maketest ()) using cppUnit_test_suite_registration (); Runner.Run (); RETURN 0;} Post-build Check, now we can already make the test run So how is it integrated into the compilation process? In order to achieve this, the application must return a non-0 value indicating an error. Testrunner :: run () Returns a Boolean value to indicate whether Run () is successful. Update our main function, we get: #include #include int main (int Argc, char ** argv) {cppunit :: textui :: TestRunner runner; CppUnit :: TestFactoryRegistry ®istry = CppUnit :: TestFactoryRegistry :: getRegistry (); runner.addTest (registry.makeTest ()); bool wasSucessful = runner.run ( "", false); return wasSucessful;} Now, you need to compile your application. With Visual C , you can add the following command in Project Settings / Post-Build Step. It is extended to the execution path of the application. Take a look at how the Project Examples / CPPUnitTest / CPPUnitTestMain.dsp is set. Original Version by Michael Feathers. Doxygen Conversion and Update by Baptiste Lepilleur.
Author: tonny Source: Reproduced