Background
CppUnit is an open source project based on LGPL, originally ported from JUnit, and is a very good open source testing framework. CppUnit and JUnit are the main ideas derived from Extreme programming (xprogramming). The main function is to manage the unit test and to automate the test. This description may not give you a sense of the power of the test framework, and did you encounter the following problems during the development process? If the answer is yes, you should learn to use this technique: test code is not well maintained and discarded, need to rewrite when testing again, put too much effort, find bugs, and new code will still appear similar bugs, write code, no bottom, whether there are a large number of bugs waiting for themselves; The newly modified code does not know whether to affect other parts of the code, because too much involved, resulting in the dare not to modify the code;
...
These questions will be covered below. This powerful test framework is not used in many of the native C + + language developers. This article introduces this framework from a developer's perspective, hoping to enable developers to master this technology at the lowest cost possible. The following are discussed in terms of basic principles, CppUnit Principles, Manual Use steps, commonly used steps, and other practical issues. The following discussion is based on CppUnit1.8.0.
|
Back to the top of the page |
|
1. Basic Principles
For the above problem only shows that the use of CppUnit is not effective, the following first from the purpose of testing, testing principles and other aspects of the brief description, and then introduce the specific use of CppUnit.
The first thing to make clear is that the purpose of writing test code is to verify the correctness of the code or debug bugs. When you write the test code, you have the pertinence of writing test code that is prone to error and variable, without having to write test code for every detail, every feature, unless you have excessive energy or reliability requirements.
The relationship between coding and testing is inseparable, the recommended development process does not have to wait to write all or a lot of code to test, but to complete a part of the code, such as a function, immediately after writing the test code to verify. Then write some code, then write the test. Each test is performed on all previous tests. The advantage of this is that, after the completion of the code, but also the basic test, the heart of the code have confidence. And in the new code to constantly test the old code, the other part of the code impact can be quickly found, positioning. The process of constantly coding tests is the process of maintaining the test code so that the test code is always valid. With the various parts of the test code to ensure that there is a mechanism for automated testing, change the previous code without any concern. In extreme programming (a concept of software development), it is even emphasized to write the test code first, and then write the code that conforms to the test code to complete the software.
According to the above purpose, thought, the following summary of the normal development process unit Test principle: First write test code, and then write the code to match the test. At least after completing some of the code, complete the corresponding test code, the test code does not need to overwrite all the details, but should have a corresponding test case for all the major functions and possible errors, find bugs, first write the corresponding test cases, and then debug, and constantly summarize the reasons for the bug Write the appropriate test cases for other code, each time you write the completion code, run all the previous test cases, verify the impact on the previous code, and eliminate the impact as soon as possible, continuously maintain the test code, ensure that the code changes after all the tests;
With the above theory as a guide, test behavior can be regulated. So CppUnit how to implement this test framework, help us manage the test code, complete the automated test. Here is a look at the principle of CppUnit.
|
Back to the top of the page |
|
2. Principle of CppUnit
In CppUnit, test subjects for one or a set of test cases are referred to as Fixture (facilities, below for easy understanding using English names as far as possible). Fixture is the target of the test, possibly an object or a group of related objects, or even a function.
With the tested fixture, you can write test code for a feature of this fixture, a potentially faulty process, so that a complete test of some aspect is called testcase (test case). Usually, the steps to write a TestCase include initializing the fixture and other initialization operations, such as generating a set of tested objects, initializing the value, manipulating the fixture according to a function or process to be tested, verifying the correctness of the results, and the fixture and its The release of his resources and other clean-up work.
For multiple test cases of fixture, typically (1) (4) Part of the code is similar, CppUnit introduces the setUp and teardown virtual functions in many places. You can complete (1) initialization of the code in the SetUp function and complete (4) code in the Teardown function. The specific test case function only needs to complete (2) (3) Part of the code, runtime CppUnit will automatically run the setUp for each test case function, then run teardown, so there is no cross impact between test cases.
All test cases for fixture can be encapsulated in a cppunit::testfixture subclass (the naming convention is [classname]test). Then define the fixture setUp and teardown functions, and define a test function for each test case (the naming convention is testxxx). Here's a simple example:
Class Mathtest:public Cppunit::testfixture { Protected int m_value1, m_value2; Public Mathtest () {} initialization function void SetUp () { M_value1 = 2; M_value2 = 3; } Test function for test addition void Testadd () { Step (2), operate on the fixture int result = m_value1 + m_value2; Step (3), verify that the results are sought Cppunit_assert (Result = = 5); } }
|
The success or failure of the test case is directly reflected in the successful or unsuccessful validation of the execution result in the test function. CppUnit provides a variety of ways to verify successful failures:
Cppunit_assert (condition) //Sure condition is true Cppunit_assert_message (message, condition) //failure when condition is false, and print message Cppunit_fail (message) //Current test failed and print message Cppunit_assert_equal (expected, Actual) /Make sure the two are equal Cppunit_assert_equal_message (message, expected, Actual) //Failed to print message at the same time Cppunit_assert_doubles_equal (expected, actual, Delta) //When the difference between expected and actual is greater than delta failure
|
To turn a test function of fixture into a test case, you need to generate a Cppunit::testcaller object. When you finally run the test code for the entire application, you may need to run multiple test functions for one fixture, or even multiple fixture test cases at the same time. In CppUnit, this collection of test cases that run concurrently is called TestSuite. Testrunner, however, runs test cases or TestSuite to manage the lifecycle of all test cases. 3 types of Testrunner are currently available, including:
Cppunit::textui::testrunner //text mode of Testrunner Cppunit::qtui::testrunner //qt mode of Testrunner Cppunit::mfcui::testrunner //MFC Way of Testrunner
|
The following is an example of a text-mode Testrunner:
Cppunit::textui::testrunner runner; Cppunit::testsuite *suite= new Cppunit::testsuite ();
Add a test case Suite->addtest (New Cppunit::testcaller<mathtest> ( "Testadd", Testadd));
Runner.addtest (suite); Start running, automatically show test progress and test results Runner.run ("", true); Run all tests and wait
|
The management of test results, display and other functions involved in another class of objects, mainly for internal testing results, progress management, as well as progress and results of the display. There is no introduction here.
Let's sort out the idea, combine a simple example, and string together the ideas above.
|
Back to the top of the page |
|
3. Manual Use Steps
The first step is to identify the object fixture the test, and then determine the test case based on its function, process, and previous experience. This step is very important and is directly related to the final effect of the test. Of course, the process of adding test cases is a phased task, after the completion of the code, complete the function of the test case, to ensure that the completion of the function, and then on the part of the possible error, combined with previous experience (such as boundary value test, path coverage test, etc.) to write test cases; Finally, when the bug Complete the test case.
For example, to test the integer addition, first define a new testfixture subclass, Mathtest, and write test code for the test case. When you need to add new test cases later, you just need to add new test functions and modify the setUp and teardown as needed. If you need to test the new fixture, define a new testfixture subclass. Note: The following code is used only to represent the principle and cannot be compiled.
///MathTest.h //A testfixture subclass. Announce:use as your owner risk. //Author:liqun (liqun@nsfocus.com) //data:2003-7-5 #include "cppunit/testfixture.h" class Mathtest : Public Cppunit::testfixture { Protected: int m_value1, m_value2; Public: Mathtest () {} //initialization function void SetUp (); //scavenging function void teardown (); //test addition test function void Testadd (); //Can add new test function }; MathTest.cpp //A testfixture subclass. Announce:use as your owner risk. //Author:liqun (liqun@nsfocus.com) //data:2003-7-5 #include "MathTest.h" #include "Cppunit/testasse Rt.h ' void Mathtest::setup () { m_value1 = 2; M_value2 = 3; } void Mathtest::teardown () { } void Mathtest::testadd () { int result = m_value1 + M_VALUE2; Cppunit_assert (Result = = 5); } |
Then write the main function, organize the test cases that need to be tested into TestSuite, then run them through Testruner. This part of the code needs to be changed a little when adding new test cases later. Just add the new test cases to the TestSuite.
Main.cpp Main file for Cppunit test. Announce:use as your owner risk. Author : Liqun (liqun@nsfocus.com) Data : 2003-7-5 Note: Cannot compile, a for study. #include "MathTest.h" #include "Cppunit/ui/text/testrunner.h" #include "Cppunit/testcaller.h" #include "cppunit/testsuite.h" int main () { Cppunit::textui::testrunner runner; Cppunit::testsuite *suite= new Cppunit::testsuite ();
Add a test case Suite->addtest (New Cppunit::testcaller<mathtest> ( "Testadd", Testadd));
Runner.addtest (suite); Start running, automatically show test progress and test results Runner.run ("", true); Run all tests and wait }
|
|
Back to the top of the page |
|
4. Common use mode
In the way above, if you want to add a new test case, you need to add each test case to the TestSuite, and adding a new testfixture needs to add all the header files to the main.cpp, which is cumbersome. For this CppUnit, Cppunit::testsuitebuilder,cppunit::testfactoryregistry and a bunch of macros are provided to facilitate the registration of testfixture and test cases into TestSuite. Here's how it's usually used:
MathTest.h A Testfixture Subclass. Announce:use as your owner risk. Author:liqun (liqun@nsfocus.com) Data:2003-7-5 #include "Cppunit/extensions/helpermacros.h" Class Mathtest:public Cppunit::testfixture { Declare a Testsuite Cppunit_test_suite (mathtest); Adding a test case to testsuite, defining a new test case requires a statement here Cppunit_test (Testadd); Testsuite Declaration Complete Cppunit_test_suite_end (); The rest is unchanged. Protected int m_value1, m_value2;
Public Mathtest () {}
initialization function void SetUp (); Cleanup function void Teardown ();
Test function for test addition void Testadd (); You can add a new test function }; MathTest.cpp A Testfixture Subclass. Announce:use as your owner risk. Author:liqun (liqun@nsfocus.com) Data:2003-7-5 #include "MathTest.h" Register this testsuite in the testsuite named "AllTest", if not defined, automatically define You can also cppunit_test_suite_registration (mathtest) and register to an unnamed testsuite in the global. Cppunit_test_suite_named_registration (Mathtest, "alltest"); The following is not changed void Mathtest::setup () { M_value1 = 2; M_value2 = 3; } void Mathtest::teardown () { } void Mathtest::testadd () { int result = m_value1 + m_value2; Cppunit_assert (Result = = 5); } Main.cpp Main file for Cppunit test. Announce:use as your owner risk. compile:g++-lcppunit MathTest.cpp main.cpp Run:./a.out Test:redhat 8.0 CppUnit1.8.0 Author:liqun (a Litthle modification. liqun@nsfocus.com) Data:2003-7-5 Do not need to include header files for all testfixture subclasses #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> If you do not change testsuite, this file does not need to be changed later. int main () { Cppunit::textui::testrunner runner;
Gets the specific testsuite from the registered Testsuite, without parameters to get the unnamed testsuite. Cppunit::testfactoryregistry ®istry = cppunit::testfactoryregistry::getregistry ("AllTest"); Add this testsuite to Testrunner Runner.addtest (Registry.maketest ()); Run Tests Runner.run (); }
|
Adding a new test case just needs to be declared at the beginning of the class definition.
|
Back to the top of the page |
|
5. Other practical issues
Typically, a test case code is included and the object being tested is in a different project. You should write testfixture in another project (preferably in a different directory), and then include the tested objects in your test project.
When testing a class or function, the testfixture may refer to other classes or other functions, in order to isolate the effects of other parts of the code, you should temporarily define some stubs in the source file to simulate these classes or functions. This code can be used in a test project through a macro definition and is not valid in the project being tested.
Reference CppUnit Home
Junittest infected:programmers Love Writing Tests
CppUnit Cookbook
Xprogramming Home
Test framework
This Code downloads
About the author
|
|
|
Lie group, currently focusing on the development of network security products, research, software development process and so on. You can contact him through liqun@nsfocus.com. |
The above is from: IBM Developer Community