CPPUnit Source Code Interpretation (2)

zhaozj2021-02-17  58

[Declaration] If you need to copy, spread, please attach this statement, thank you. Original source: http://morningspace.51.net/ ,moyingzz@etang.com

Basic test related classes

In CPPUnit, there is a consistent most basic Pattern, which is Composite Pattern. This pattern is described in GOF: combine the object into a tree structure to represent a "part-overall" hierarchy. Composite enables users to have consistency for a single object and combined object. In the framework of CPPUnit, the test class is divided into two, some test classes represent a single test, such as TestCase (test case), and other test classes, such as TestSuite, which is told later. (Test package). TestCase associated with each other constitutes a TestSuite, and TestSuite can also be nested. Both respectively correspond to Leaf and Composite in Composite Pattern.

[TEST]

Related Documents: Test.h

This is the abstract base class of all test classes, which specifies the behavior of all test classes, corresponding to Component in Composite Pattern, in addition to the standard Virtual DTOR, also defined four pure virtual functions:

// Run the test content and use the TestResult to collect the test results in its TestResult, similar to the Operation operation similar to Component

Virtual Void Run (TestResult * Result) = 0;

/ / Returns the number of currently included test objects, if TestCase, returns 1.

Virtual int counttestcases () const = 0;

/ / Return to the name of the test, each test has a name, like an identifier, to find or display

Virtual st :: string getname () const = 0;

// This test is a short description for debugging output.

// In addition to the name of the test, there may be other information,

// For example: a test package called "Complex_ADD" may be described as "Suite Complex_ADD"

Virtual st :: string toString () const = 0;

[TestFixTure]

Related Documents: TestFixTure.h

This class is also an abstract class that has a setup method and a Teardown method for packaging test classes. With it, you can provide a set of related tests (ie, so-called fixture). To achieve this, you need:

From TestFixTure, a subclass is derived from TestCase, which is relatively convenient, so that it is more convenient, seeing the instance variable (INSTANCE VARIABLES) to form a FixTure Reserved SETUP initialization FixTure's status heavy load TEARDOWN after test Resource recycling

In addition, as a complete test class, it is also necessary to define some test methods for performing specific test tasks, and then tested using TestCaller. About TestCaller, will talk in the Helper section. Because each test object runs in its own fix, there will be no side effects between the test objects, and the test method inside the test object uses the same FixTure. Take a look at the definition of TestFixTure, in addition to the standard Virtual DTOR, two pure virtual functions have also been defined: // Set the context before running the test, that is, fixup is more important, unless the instance variable is created In HEAP, otherwise, its resource recovery does not need to handle it.

Virtual void setup () {};

// Recycling resources after the test run

Virtual void teardown () {};

[TestCase]

Related documents: Testcase.h, testcase.cpp

Derive from Test and TestFixTure, both characteristics, for implementing a simple test case. What you have to do is derived such, and overload the Runtest method. But usually don't have to be the case, but use TestCaller to combine TestFixTure method, which is convenient. When you find TestCaller unable to meet, you need to rewrite a class of features, and use TestCase is not too late. About TestCaller, will talk in the Helper section.

The most important way in TestCase is the RUN method, come and see the code, please pay attention to Morning annotations:

Void Testcase :: Run (TestResult * Result)

{

// Don't care about StartTest's specific behavior, you will naturally understand when talking about TestResult.

This is true for endtest at the end of //

Result-> StartTest (this);

Try {

// Set FixTure, the specific content needs to be derived to solve

/ / May have an abnormality, after processing

setup ();

// Runtest has a protected property that is a function of truly executing tests.

/ / But the specific behavior needs to be derived.

Try {

Runtest ();

}

/ / May throw an exception when the test is run, the following is an abnormal process

Catch (Exception & E) {

// a application of Prototype Pattern

// e is a temporary object, and the AddFailure is destroyed, so you need to create a copy.

EXCEPTION * COPY = E.Clone ();

Result-> AddFailure (this, copy);

}

Catch (std :: eXception & e) {

// Unusual method for exception - Transaction

Result-> Adderror (this, New Exception (E.WHAT ()));

}

Catch (...) {

// Intercept the rest, unknown, one network

Exception * E = New Exception ("Caught Unknown Exception");

Result-> Adderror (this, E);

}

// Recycle

Try {

TEARDOWN ();

}

Catch (...) {

Result-> Adderror (THIS, New Exception ("Teardown () Failed");

}

Catch (...) {

Result-> Adderror (THIS, New Exception ");

}

Result-> Endtest (this);

}

It can be seen that the RUN method defines the basic behavior of a test class and its order:

Setup: Prepare Runtest: Start TEARDOWN: End, TestCase as an abstract class unable to determine the specific behavior of the test, so you need to leave a class solution, which is Template Method Pattern. In fact, this pattern is very common in Framework. Therefore, a completely test method is to derive a class, overloading related methods from TestCase, and call the RUN method (as mentioned in TestFixTure). Interestingly, there is another version of Run in TestCase, which has no shape, but creates a default TestResult, and then calls the RUN method. But it seems that it is not used, it is probably the garbage code that has not been cleaned up before debugging. It is no wonder that there will be "fixme: what is this for?". Testcase has two ctor: testcase (std :: string name); // Name of the test class

Testcase ();

The latter is mainly used for TestCaller, because when using TestCaller, you need a default ctor [strange, the compiler can automatically generate the default ctor, do you don't paint the snake to add, remove the function, you can run it], Testcase will be Copy CTOR And operator = declare as a Private property to prevent misuse.

[Testsuite]

Related Documents: Testsuite.h, Testsuite.cpp

A group of interrelated test cases constitute a test package, which is TestSuite, which is Composite Pattern. Like TestCase, also sent from Test, just no fixture feature. In addition to the name of the test class, a test object array is also maintained in TestSuite, which is declared as a private property:

Std :: Vector m_tests; // Can you use Vector ? ]

Const std :: string m_name;

Take a look at how the TestSuite's RUN method is implemented, please pay attention to MORNING Note:

Void Testsuite :: Run (TestResult * Result)

{

// Traverse VECTOR

For (std :: vector :: item = m_tests.begin ();

It! = m_tests.end ();

IT)

{

// may be terminated in the middle

if (Result-> ShouldStop ())

Break;

TEST * TEST = * IT;

// Call each Test's own RUN

/ / May be a TestCase instance, or it may be a TestSuite instance, // The latter forms a recursive, but it is completely unknown here.

TEST-> Run (Result);

}

}

About TestResult and its ShouldStop method, will be told later. However, Break here is also an easy example of the use of Composite Pattern. From the perspective of efficiency, when it is believed that it is not necessary to perform subsequent TEST, it can be returned directly instead of the rum of Test's RUN method.

Since TestResult is derived from Test, how is the counttestcases implement it:

Int testsuite :: counttestcases () const

{

INT count = 0;

// Traverse VECTOR

For (std :: vector :: const_iterator it = m_tests.begin ();

It! = m_tests.end ();

IT)

Count = (* IT) -> countTestCases (); // Recursively calls each test attestcases, and accumulate

Return count;

}

As for addtest, it is naturally unable to be less, it corresponds to the Add method of Composite:

Void Testsuite :: AddTest (Test * Test)

{

m_tests.push_back (test); // Add Test to the end of the array of test objects

}

However, please note that the AddTest method has not appeared in an abstract class TEST, and the trade-offs in this type of design is in GOF, and the Composite Pattern section has special discussion.

TestSuite manages the life cycle of the test objects, in the DTOR, it will call the deleteContents method:

Void testsuite :: deleteContents ()

{

For (std :: vector :: item = m_tests.begin ();

It! = m_tests.end ();

IT)

Delete * it;

m_tests.clear ();

}

In addition, TestSuite provides an interface for external access to its own test object, because the return value is const & type, so it is Read-Only:

Const std :: vector & gettests () const;

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

New Post(0)