CPPUnit Source Code Interpretation (3)

zhaozj2021-02-17  55

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

Test results record related

From here, the relevant part of the test results record will be described in CORE.

CPPUnit is supported multithreaded, you can perform tests in a thread, collect test results in another thread; or perform multiple tests in parallel in different threads, and use a thread to collect test results. This provides a brief and necessary support for this in Framework.

[SynchronizedObject]

Related Documents: SynchronizedObject.h, synchronizedObject.cpp

SynchronizedObject is used to manage a synchronous object, and the TestResult mentioned earlier is derived from this class. The so-called synchronous object refers to the use of a number of threads to be used concurrently.

SynchronizedObject defines the Abstract Inner Class - SynchronizationObject of a public property, represents an object with synchronous properties:

Class synchronizationObject

{

PUBLIC:

SYNCHRONIZATIONObject () {}

Virtual ~ synchronizationObject () {}

Virtual void lock () {}

Virtual void UNLOCK () {}

}

Such a mutex function is defined, but the specific behavior needs to be implemented in its derived class. Implementation methods in different environments must also be the same. In the example attached to the CPPUnit source, there is a subclass of SynchronizationObject, which uses MFC's ccriticalSection: Class MfcsynchronizationObject.

: Public CPPUnit :: SynchronizedObject :: SYNCHRONIZATIONObject :: SYNCHRONIZABJECT

{

CcriticalSECTION M_SYNCOBJECT;

PUBLIC:

Void Lock ()

{

m_syncObject.lock ();

}

Void unlock ()

{

m_syncObject.unlock ();

}

}

SynchronizedObject also defines the Inner Class - Exclusivezone of a protected property, as an auxiliary class for internal use. It is used to lock an instance of a SynchronizationObject in the current scope. It is realized similar to std :: auto_ptr, which holds a pointer to the SYNCHRONIZATIONObject object, CTOR calls Lock, DTOR, call unlock: Class Exclusivezone

{

SynchronizationObject * m_syncobject;

PUBLIC:

Exclusivezone (SynchronizationObject * SyncObject)

: m_syncObject (SyncObject)

{

m_syncObject-> lock ();

}

~ Exclusivezone ()

{

m_syncObject-> unlock ();

}

}

Remove these, SynchronizedObject is very simple. It holds a pointer to the SynchronizationObject instance: synchronizationObject * m_syncobject;

And manage its life cycle, delete in the DTOR. As for how to pass the pointer, two methods are provided: SynchronizedObject :: synchronizationObject (synchronizationObject * syncobject): m_syncObject (SyncObject == 0? New synchronizationObject ():

SYNCOBJECT)

{

}

Void SynchronizedObject :: setsynchronizationObject (SynchronizationObject * SyncObject)

{

Delete M_SyncObject;

M_SyncObject = SyncObject;

}

Before telling TestResult, there are some obstacles to clean.

[TestListener]

Related Documents: Testlistener.h

CPPUnit's test results record uses Observer Pattern, which is described below in GOF: a one-to-many dependencies between the objects, when the status of an object changes, all objects depend on it Notification and automatic update. During the test execution, TestResult will be informed when an error occurs, and it will pass the information to the TestListener. Therefore, TestResult corresponds to the Subject in Observer Pattern, and TestListener corresponds to Observer.

However, TestListener is just a base class that does not do, like the output test results, so things have to be derived to resolve, such as the TEXTTESTPROGRESSLISTENER to which the Outputter section is mentioned. Also, try not to use Listener to perform the output of test results, and you should use the proprietary tools provided in Outputter.

From the definition of TestListener, you can see that TestListener will be notified when the following three types of events occur.

After the test failed test execution

Take a look at the code: // is called before a test run

Virtual Void StartTest (Test * Test) {}

// is called when running test failure

Virtual Void Addfail (Const Testfail & Fail)

// is called after a test run

Virtual Void Endtest (Test * Test)

The Failure in AddFail is a temporary object, which is destroyed after the method is called, and the Exception is the same (see TestCase's Run function), and it is also necessary to use its own CLONE method to create a copy. About TestFailure, will be mentioned later. As for EndTest, even if the test fails, the function will also be called, see the RUN function of TestCase.

[TestResult]

Related Documents: TestResult.h, TestResult.cpp

It's really a thousand calls. TestResult is used to collect information in the test process, which is derived from SynchronizedObject to support multithreading. With the front floor, it is very easy to understand TestResult.

TestResult maintains a pointer queue to the TestListener object:

protected:

Typedef std :: deve testlisteners;

TestListener M_Listener; TestListener needs to be registered in TestResult, so there is AddListener method: Void TestResult :: AddListener (Testlistener * listener)

{

Exclusivezone Zone (m_syncobject); // Exclusivezone finally used Wu's land

m_listeners.push_back (listener);

}

Of course, there is still a remodelistener: void TestResult :: Removelistener (Testlistener * listener)

{

Exclusivezone Zone (m_syncobject);

M_Listeners.rase (std :: remove (m_listener.begin (),

M_Listeners.end (),

Listener,

m_listeners.end ());

}

Let's take a look at TestResult as the NOTIFY method of Subject: Void TestResult :: AdDerror (Test * Test, Exception * E)

{

AddFailure (Testfailure (Test, E, TRUE);

}

Void TestResult :: AddFailure (Test * Test, Exception * e)

{

AddFailure (TestFailure (Test, E, FALSE);

}

Void TestResult :: AddFail (Const Testfailure & Fail)

{

Exclusivezone Zone (m_syncobject);

// Traverse Deque

For (Testlistener :: item IT = m_listeners.begin ();

It! = m_listeners.end ();

IT)

(* IT) -> addfailure (failure); // Call TestListener's AddFail

}

Void TestResult :: StartTest (Test * Test)

{

Exclusivezone Zone (m_syncobject);

// Traverse Deque

For (Testlistener :: item IT = m_listeners.begin ();

It! = m_listeners.end ();

IT)

(* IT) -> StartTest (TEST); // Call the StartTest of TestListener

}

Void TestResult :: endtest (test * test)

{

Exclusivezone Zone (m_syncobject);

// Traverse Deque

For (Testlistener :: item IT = m_listeners.begin ();

It! = m_listeners.end ();

IT)

(* IT) -> endtest (test); // Call TestListener's EndTest

}

The annotations here are sufficient to explain the problem, as for the difference between Error and Failure, naturally it will be clear when TestFailure. Finally, let's take a look at the code of ShouldStop, which has appeared in the TestSuite's Run: TestResult :: TestResult (SynchronizationObject * SyncObject): SYNCHRONIZEDOBJECT (SYNCOBJECT)

{

RESET ();

}

Void TestResult :: RESET ()

{

Exclusivezone Zone (m_syncobject);

m_stop = false;

}

Bool TestResult :: ShouldStop () Const

{

Exclusivezone Zone (m_syncobject);

Return M_Stop;

}

Void testResult :: stop ()

{

Exclusivezone Zone (m_syncobject);

m_stop = true;

}

Nothing special, just a m_stop is controlling everything, and m_stop is a member variable of a protected property of TestResult: BOOL M_STOP;

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

New Post(0)