Convenient development tool cppunit Quick Start Guide

Source: Internet
Author: User
Tags naming convention
August 03, 2003
This article introduces the cppunit framework from the perspective of developers, hoping that developers can grasp this technology at the minimum cost as soon as possible. The following describes the basic principle, cppunit principle, manual steps, general steps, and other practical problems. The following is based on cppunit1.8.0.

Background
Cppunit is an open-source lgpl-based project. It was originally transplanted from JUnit and is an excellent open-source testing framework. Cppunit is the same as JUnit. Its main idea comes from xprogramming ). The main function is to manage unit tests and perform automated tests. This description may not allow you to experience the powerful power of the test framework. Do you encounter the following problems during development? If the answer is yes, you should learn to use this technology:

  • The test code is not well maintained and discarded. It must be rewritten when testing again;
  • Put too much effort into finding bugs, and new code will still have similar bugs;
  • After writing the code, I have no idea whether there are a lot of bugs waiting for myself;
  • The newly modified code does not know whether it affects other parts of the Code;
  • The Code cannot be modified because it involves too many tasks;
    ...

These questions will be covered below. This powerful testing framework is not widely used by C ++ developers in China. This article introduces this framework from the perspective of developers, hoping that developers can grasp this technology at the minimum cost as soon as possible. The following describes the basic principle, cppunit principle, manual steps, general steps, and other practical problems. The following is based on cppunit1.8.0.

1. Basic Principles
The above problems only show that the use of cppunit is ineffective. The following describes the purpose and principles of the test, and then introduces the specific use of cppunit.

First, we need to clarify the purpose of writing test code, that is, to verify the code correctness or debug bugs. In this way, the test code is written in a targeted manner, and the test code for those that are prone to errors and changes does not need to be compiled for every detail and every function, of course, unless there are excessive energy or reliability requirements.

The relationship between coding and testing is inseparable. The recommended development process does not have to wait until all or a lot of code is compiled before testing. Instead, it completes some code, such as a function, then immediately write the test code for verification. Then write some code and test again. All previous tests are performed in each test. The advantage of this is that you have confidence in the code after writing the code and testing it again. In addition, the old code is constantly tested when writing new code, and the impact on other parts of the code can be quickly discovered and located. The process of Continuous Coding testing is the process of maintaining the test code so that the test code is always effective. With the assurance of various parts of the test code and the automatic testing mechanism, there is no concern for changing the previous code. In extreme programming (a software development idea), I even emphasized writing test code first, and then writing code that conforms to the test code to complete the entire software.

Based on the purposes and ideas mentioned above, we will summarize the unit testing principles in the development process below:

  • First, write the test code, and then write the code that conforms to the test. After at least some code is completed, the corresponding test code is completed;
  • The test code does not need to cover all details, but should have corresponding test cases for all main functions and possible errors;
  • When a bug is detected, write the corresponding test case and debug it;
  • Constantly summarize the causes of bugs and write test cases for other codes;
  • Each time the Code is compiled, all previous test cases are run to verify the impact on the previous Code and eliminate this impact as soon as possible;
  • Continuously maintain the test code to ensure that all tests are passed after the code changes;

With the guidance of the above theories, the test behavior can be followed. So how does cppunit implement this testing framework to help us manage test code and complete automatic testing? Next let's take a look at the principles of cppunit.

2. Principles of cppunit
In cppunit, one or more test cases are called fixture ). Fixture is the target to be tested. It may be an object, a group of related objects, or even a function.

With the tested fixture, you can write test code for a certain function of the fixture and a process that may fail. In this way, a complete test of a certain aspect is called testcase (test case ). The steps for writing a testcase generally include:

  1. Initialize fixture and other initialization operations, such as generating a group of tested objects and initializing values;
  2. Operate the fixture according to a function or process to be tested;
  3. Check whether the verification result is correct;
  4. Clear fixture and its resource release.

For multiple fixture test cases, part of the code (1) (4) is usually similar. cppunit introduces the setup and teardown virtual functions in many places. You can complete (1) initialization code in the setup function, and (4) code in the teardown function. You only need to complete Part of the Code (2) (3) in the specific test case function. During running, cppunit automatically Runs Setup for each test case function, and then runs teardown, in this way, 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 setup and teardown functions of the fixture, and define a test function for each test case (the naming convention is testxxx ). The following is a simple example:



Class mathtest: Public cppunit: testfixture {
Protected:
Int m_value1, m_value2;

Public:
Mathtest (){}

// Initialize the Function
Void setup (){
M_value1 = 2;
M_value2 = 3;
}
// Test the addition test function
Void testadd (){
// Step (2) to operate the fixture
Int result = m_value1 + m_value2;
// Step (3) to verify whether the result is obtained
Cppunit_assert (result = 5 );
}
// There is no cleanup task and no teardown is defined.
}

The success or failure of the execution result in the test function directly reflects the success and failure of the test case. Cppunit provides multiple methods for successful verification failures:



Cppunit_assert (condition) // make sure the condition is true.
Cppunit_assert_message (message, condition) // if the condition is false, it fails and the message is printed.
Cppunit_fail (Message) // the current test fails and the message is printed.
Cppunit_assert_equal (expected, actual) // make sure the two are equal
Cppunit_assert_cmd_message (message, expected, actual) // print the message when the request fails.
Cppunit_assert_doubles_equal (expected, actual, Delta) // failure when the difference between expected and actual is greater than Delta

To convert a test function of fixture into a test case, you need to generate a cppunit: testcaller object. When you finally run the test code of the entire application, you may need to run multiple test functions or even multiple fixture test cases for one fixture at the same time. Cppunit calls the set of such concurrent test cases testsuite. Testrunner runs the test case or testsuite to manage the lifecycle of all test cases. Currently, three types of testrunner are provided, including:



Cppunit: textui: testrunner // testrunner in text mode
Cppunit: qtui: testrunner // testrunner in QT Mode
Cppunit: mfcui: testrunner // testrunner In the MFC Mode

The following is an example of the 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 ));

// Specify to run testsuite
Runner. addtest (suite );
// Start running and automatically display the Test Progress and test results
Runner. Run ("", true); // run all tests and wait

The management and display of test results involve another type of objects. They are mainly used for internal management of test results and progress, as well as display of progress and results. We will not introduce it here.

Next we will sort out our ideas and link them together with a simple example.

3. manual steps
First, define the test object fixture, and then determine the test case based on its functions, procedures, and previous experience. This step is very important and is directly related to the final result of the test. Of course, the process of adding test cases is a step-by-step process. After the code is completed, the function test cases are completed to ensure that the functions are completed, write test cases based on previous experience (such as boundary value test and path coverage test). Finally, complete the test case based on the bug when detecting the relevant bug.

For example, to test integer addition, first define a new testfixture subclass, mathtest, and write the test code of the test case. To add new test cases later, you only need to add new test functions and modify setup and teardown as needed. To test the new fixture, define the new testfixture subclass. Note: The following code only indicates 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

# I nclude "cppunit/testfixture. H"


Class mathtest: Public cppunit: testfixture {
Protected:
Int m_value1, m_value2;

Public:
Mathtest (){}

// Initialize the Function
Void setup ();
// Clear the Function
Void teardown ();

// Test the addition test function
Void testadd ();
// You can add new test functions.
};

/// Mathtest. cpp
// A testfixture subclass.
// Announce: use as your owner risk.
// Author: Liqun (liqun@nsfocus.com)
// Data: 2003-7-5

# I nclude "mathtest. H"
# I nclude "cppunit/testassert. 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 to be tested into testsuite, and then run them through testruner. This part of code does not need to be changed much when new test cases are added later. You only need to add a new test case to 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, only for study.
# I nclude "mathtest. H"
# I nclude "cppunit/UI/text/testrunner. H"
# I nclude "cppunit/testcaller. H"
# I nclude "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 ));

// Specify to run testsuite
Runner. addtest (suite );
// Start running and automatically display the Test Progress and test results
Runner. Run ("", true); // run all tests and wait
}

4. Common usage
According to the above method, to add a new test case, you need to add each test case to testsuite, and add all header files to main. CPP. Cppunit provides cppunit: testsuitebuilder, cppunit: testfactoryregistry, and a bunch of macros to conveniently register testfixture and test cases to testsuite. The following is the common usage:



/// Mathtest. h
// A testfixture subclass.
// Announce: use as your owner risk.
// Author: Liqun (liqun@nsfocus.com)
// Data: 2003-7-5

# I nclude "cppunit/extensions/helpermacros. H"


Class mathtest: Public cppunit: testfixture {
// Declare a testsuite
Cppunit_test_suite (mathtest );
// Add a test case to testsuite. Declare the new test case here.
Cppunit_test (testadd );
// Testsuite declaration complete
Cppunit_test_suite_end ();
// The rest remain unchanged

Protected:
Int m_value1, m_value2;

Public:
Mathtest (){}

// Initialize the Function
Void setup ();
// Clear the Function
Void teardown ();

// Test the addition test function
Void testadd ();
// You can add new test functions.
};

/// Mathtest. cpp
// A testfixture subclass.
// Announce: use as your owner risk.
// Author: Liqun (liqun@nsfocus.com)
// Data: 2003-7-5

# I nclude "mathtest. H"

// Register this testsuite to the testsuite named "alltest". It will be automatically defined if it is not defined.
// You can also use cppunit_test_suite_registration (mathtest); to register it to a globally unnamed testsuite.
Cppunit_test_suite_named_registration (mathtest, "alltest ");

// The following remains unchanged

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

// You do not need to include all header files of the testfixture subclass.
# I nclude <cppunit/extensions/testfactoryregistry. h>
# I nclude <cppunit/UI/text/testrunner. h>

// If testsuite is not changed, this file does not need to be changed later.

Int main ()
{
Cppunit: textui: testrunner runner;

// Obtain the specific testsuite from the registered testsuite. No parameter is provided to obtain the Untitled testsuite.
Cppunit: testfactoryregistry & registry = cppunit: testfactoryregistry: getregistry ("alltest ");
// Add this testsuite to testrunner
Runner. addtest (registry. maketest ());
// Run the test
Runner. Run ();
}

To add a new test case, you only need to declare it at the beginning of the class definition.

5. Other practical problems
Generally, the code that contains the test case and the tested object are in different projects. You should write testfixture in another project (preferably in different directories) and include the tested objects in the test project.

When testing a class or function, this testfixture may reference other classes or functions. to isolate the impact of other code, you should temporarily define some program in the source file, simulate these classes or functions. The code can be valid in the test project through macro definition, but not in the tested project.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.