CPPUNIT COOKBOOK Chinese version

zhaozj2021-02-17  74

This is my first complete translation article. Welcome everyone, contact me: zgump@sina.com

*********************************************************** *******************************

This article is a simple entry guidance to help you get started quickly.

Simple Test Case (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, these are what you have to do:

Delicate a class 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 comparison of a complex class, write as follows:

Class ComplexNumbertest: PUBLIC CPPUNIT :: Testcase {public: complexNumbertest (std :: string name): cppunit :: testcase (Name) {} 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 establish the above ComplexNumbertest test case, compile them what will happen. The first thing we noticed is to have some compilation errors. The test uses the operator ==, but it is not defined. amend as below:

Bool Operator == (Const Complex & A, Const Complex & B) {Return True;}

Now compile and run again. This compilation passed, but did not pass the test. We need to write some code to make the operator == can work correctly, so we will modify 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) && (A.Imaginary, B.Imaginary);} If we are compiled and run, you can pass the test smoothly. .

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 operators , and any other operators during the development process.

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 is the test class we added to some extra cases method: 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 test_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 instance below for each test case: cppunit :: testcaller Test ("Testequality", & complexNumbertest :: Testequality); cppunit :: testResult result; test.run (& result);

The second parameter of the constructor of the TestCaller is the address of the corresponding 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); Suite.Run (& Result);

TestSuites does not have to contain only test cases of Caller. They can include any object that implements TEST interfaces. 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.Addtest (Suite.Run (SURREALNUMBERTEST :: Suite ()); Suite.Run (& Result); Suite.Run (& result); Suite.run (& result);

Testrunner How do you run your use case 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 file is included in main.cpp: #include #include "exampleestcase.h" #include "complexnumbertest.h"

Then add AddTest (cppunit :: test *) in main (): int Main (int Argc, char ** argv) {cppunit :: textui :: Testrunner Runner; runner.addtest (Exampletestcase :: suite ()) Runner.addtest (ComplexNumbertest :: Suite ()); runner.run (); return 0;}

Testrunner will run 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 written to 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 the macro: cppUnit_test_suite (ComplexNumbertest);

This Suite built using a static suite () Method is named in the name of the class. Then we declare each test case: cppUnit_test (testequality); cppunit_test (testaddition);

Finally, we end this Suite declaration: cppunit_test_suite_end (); here next to Method has been implemented: static cppunit :: testsuite * suite ();

The remaining fixture keeps 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 test_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);}};

The name of the TestCaller joined to this Suite is the combination of this fixture name and Method name. For this use case, the name is "ComplexNumbertest.Testequality" and "ComplexNumbertest.testaddition".

Helper Macros helps you write some common 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. * Write this test case for Method

CPPUNIT_TEST_SUITE (COMPLEXNUMBERTEST); // [...] cppUnit_test_exception (TestDiDebyzerothrow, Mathexception); cppUnit_test_suite_end ();

// [...]

Void testdividebyzerothrows () {// The folload line shouth; * 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 ComplexNumber Suite, add: #include

CPPUNIT_TEST_SUITE_REGISTRATION (COMPLEXNUMBER);

In fact, the action under the desktop is that 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;

First we get an instance of TestFactoryRegistry: CppUnit :: TestFactoryRegistry & registry = CppUnit :: TestFactoryRegistry :: getRegistry (); and then we get to add a new TestSuite generated by TestFactoryRegistry, which includes the use of CPPUNIT_TEST_SUITE_REGISTRATION () registration of all test suite Runner.addtest (); runner.run (); return 0;}

POST-Build Check is ok, now we can make the test run, how about it to integrate it 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 & registry = 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.

转载请注明原文地址:https://www.9cbs.com/read-31344.html

New Post(0)