CPPUNIT - Test drive development
http://www.polyrandom.com/content/view/17//
CPPUNIT - Test drive development
Pen: Administrator User Rating: / 3
Good
2004-10-09
Test driver development is one of the most popular vocabulary now, but many people are still not entitled. This article wanted to give readers a basic image by introducing CPPUnit. If you are familiar with CPPUnit, please refer to my article: CPPUnit Code Introduction - The first part, the core class is obtained for further understanding for CPPUnit.
I. Preface
Test driver development is one of the most popular vocabulary now, but many people are still not entitled. This article wanted to give readers a basic image by introducing CPPUnit. If you are familiar with CPPUnit, please refer to my article: CPPUnit Code Introduction - The first part, the core class is obtained for further understanding for CPPUnit.
Ii. Test driver development
To understand test drive development, you must first understand the test. The test is to determine if there is known or unknown error in the source code through the detection of the source code or otherwise detection. The so-called test driver development is based on the requirements of the program that will be developed before development, and all the test code is written, and the test code is obtained from time to time by running the test code from time to time. gap. Many people may have questions: Since I haven't started writing code yet, how can I write test code? This is because, although we have not written any implementation code, we can write the test code from the user from the perspective of the code according to our requirements of the code. In fact, before the development of test code, you can detect that your request is perfect and accurate, because if you can't write test code, you can't clear enough.
This article demonstrates the advantages of test driver development relative to common development methods through a file status operation class.
III. File Status Operation Class (FileStatus)
Constructor, accept a const std :: string & as a file name parameter.
DWORD getFileSize () functions get the length of this file.
The BOOL FILEXISTS () function is available for this file.
Void SetFileModifyDate (FileTime FT) function sets the modification date of this file.
Filetime getFileModifyDate () function returns the modification date of this file.
The std :: string getFileName () function returns the name of this file.
Introduction to IV. CPPUnit
The test we conducted, in a sense, is one or more functions. By running these functions, we can detect if we have errors. Suppose we have to test the constructor and getFileName function, there is a clear invariant that is the call to a filestatus :: getFileName function, which should be the same as the parameter transmitted to this FileStatus object. So we have such a function:
Bool TestCToRandGetFileName ()
{
Const string filename ("a.dat");
FILESTATUS STATUS (FileName);
Return (status.getfilename () == filename);
}
We only need to test the return value of this function, you can know if it is correct. In CPPUnit, we can send a class from TestCase and overload its RunTest function.
Class mytestcase: PUBLIC CPPUNIT_NS :: Testcase {
PUBLIC:
Virtual void runtest ()
{
Const std :: string filename ("a.dat");
FILESTATUS STATUS (FileName);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), filename);
}
}
CPPUNIT_ASSERT_EQUAL is a macro that will throw an exception when its two parameters are unequal. Therefore, in theory, we can pass:
Mytestcase m;
m.Runtest ();
To test, if there is an abnormality, then the code is wrong. However, this is obviously inconvenient, nor is it the original intention to use CPPUnit. Below we give the complete code:
// UnitTest.cpp: Defines the entry point for the console application.
//
#include "cppUnit / testcase.h"
#include "cppunit / testResult.h"
#include "cppunit / textOutputter.h"
#include "cppUnit / testResultCollector.h"
#include
#include
Class Filestatus
{
Std :: string mfilename;
PUBLIC:
FileStatus (const st: string & filename): mfilename (filename)
{}
Std :: string getFilename () const
{
Return mfilename;
}
}
Class mytestcase: public cppUnit_ns :: testcase
{
PUBLIC:
Virtual void runtest ()
{
Const std :: string filename ("a.dat");
FILESTATUS STATUS (FileName);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), filename);
}
}
int main ()
{
Mytestcase m;
CPPUNIT_NS :: TestResult R;
CPPUNIT_NS :: TestResultCollector Result
R.AddListener (& result);
M.Run (& r);
CPPUNIT_NS :: TextOutputter Out (& Result, std :: cout);
Out.write ();
Return 0;
}
Here I will talk about how to run this program. Suppose your CPPUnit version is 1.10.2, after extracting, you will find a cppunitlibraries.dsw in the SRC folder, open it, and compile. You will find some lib and dlls in the lib folder, and our program needs to be dependent on. Next, create a Console application, suppose we use only debug mode, in Project Settings, select the Precompile Option (Precompiled Header), add the CPPUnit's Include path to Additional Include Directories, and change the code generation Multi-Threaded Debug DLL then adds cppUnitd.lib to your project. Finally, replace the main.cpp in our file. At this time, you can compile it. In this file, the front four lines are the corresponding header files of CPPUnit. In CPPUnit, usually a class is defined in the header file named after it. Then there is our String and Iostream header files. Then there is a simple implementation of our class, only the meaningful features in this test. Next is our TestCase definition, cppUnit_ns is the namespace where CPPUnit is located. In Main, TestResult is actually a test controller. When you call TestCase's RUN, you need to provide a TestResult. As the test of the test, the information generated in the test will be sent to TestResult, and the TestResult is used as a distributor to forward the received information to its Listener. That is, I simply define a TestResult and pass its pointer to Testcase :: run, this program can also be compiled and run correctly, but it does not have any output. TestResultCollector can collect the information of the test output and finally output through the TextOutputter. In the above example, the output you get is:
OK (1 tests)
This shows that we have conducted a total of 1 test and passed. If we are human to change the "returna mfilename;" "Return MfileName 'A';" to create an error, then the results of the test becomes:
!!! Failures !!!
Test Results:
Run: 1 Failures: 1 Errors: 0
1) TEST: (f) Line: 31 C: UnitTestUnitTest.cpp
Equality assertion failed
- EXPECTED: A.DATA
- Actual: a.dat
This result tells us that our implementation has problems. As mentioned earlier, cppUnit_assert_equal will throw an exception when two parameters are not equal, but why is there no abnormality to quit? This is because when we execute every TestCase's Run, it uses a special mechanism to pack the function, and any exception will be captured. For details, please refer to my CPPUnit code.
If we replace #include "cppunit / textoutputter.h" replacement into a #include "cppunit / compileroutputter.h", and replace the TextOutput to compileroutputTer, the output is turned:
C: UnitTestUnitTest.cpp (32): Error: AssertionTest Name:
Equality assertion failed
- EXPECTED: A.DATA
- Actual: a.dat
Failures !!!
Run: 1 Failure Total: 1 Failures: 1 Errors: 0
This output, in the information window of the compiler, you can reach the appropriate location by double-clicking the line of the file name plus line number.
V. Iterative development
In the above example, we write test cases in part of the demand, and then achieve the corresponding functionality. After these features are tested, we will continue to implement test cases of other features, then continue to implement the corresponding functions. This is an iterative process, which continues to increase the test case and implement code, and finally reach a demand. Another way is to write all the test cases (this time it usually does not pass), then add the implementation that can make compilation through the required implementation (this time there will be a lot of errors), followed by correct implementation Make no test errors, finally, optimize and update the code, and keep the test pass. Here we focus on the second method. First we write all the test cases first, here, because there are many test cases, we no longer use TestCase, because TestCase is usually used in a single test task. This time we derive our test class from TestFixTure:
Class mytestcase: public cppUnit_ns :: testfixture
{
PUBLIC:
void testorendgetname ()
{
Const std :: string filename ("a.dat");
FILESTATUS STATUS (FileName);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), filename);
}
Void testGetFilesize ()
{
Const std :: string filename ("a.dat");
FILESTATUS STATUS (FileName);
CPPUNIT_ASSERT_EQUAL (status.getfilesize (), 0); //?
}
}
Writing here, we found two questions, first we keep in initializing some of the objects needed to test, repeating a lot of code; second we discover an interface design error, our interface is not considered a file does not exist Happening. It can be seen from it, write test cases, not only the test of the implementation, but also the test of our design. TestFixTure defines two member functions setup and Teardown, when each test case is executed, and it defines the SETUP and TEARDOWN inside the same class to be called to initialize and clear work. We can use these two functions to make a unified initialization code. Also, we modify GetFileSize, setFileModifyDate and getFileModifyDate so that they throw an exception FileStatuserror when there is an error. Here is our test case:
Class mytestcase: public cppUnit_ns :: testfixture
{
Std :: string mfilenameexist;
Std :: string mfilenamenotexist;
Std :: string mtestfolder;
ENUM DUMMY
{
FILE_SIZE = 1011
}
PUBLIC:
Virtual void setup () {
MTESTFOLDER = "C: JustFortest";
MfileNameexist = mtestfolder "exist.dat";
Mfilenamenotexist = mtestfolder "notexist.dat";
IF (getFileAttributes (mtestfolder.c_str ())! = invalid_file_attributes)
Throw std :: Exception ("Test Folder Already Exists);
IF (! Createdirectory (mtestfolder.c_str (), null)
Throw std :: Exception ("Cannot Create Folder);
Handle file = cretefile (mfilenameexist.c_str (), generic_read | generic_write,
0, NULL, CREATE_NEW, 0, NULL);
IF (file == invalid_handle_value)
Throw std :: Exception ("cannot create file");
CHAR BUFFER [file_size];
DWORD BYTESWRITTEN
IF (! Writefile (File, Buffer, File_Size, & Byteswritten, Null) ||
Byteswritten! = file_size)
{
CloseHandle (file);
Throw std :: Exception ("cannot write file");
}
CloseHandle (file);
}
Virtual Void Teardown ()
{
IF (! deletefile (mfilenameexist.c_str ())))
Throw std :: Exception ("cannot delete file");
IF (! RemoveDirectory (mtestfolder.c_str ())))
Throw std :: Exception ("Cannot Remove Folder";
}
void testorendgetname ()
{
Filestatus status (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), mfilenameexist;
}
Void testGetFilesize ()
{
FileStatus exist (mfilenameexist);
// Here, File_Size default is int, and getFileSize returns DWORD, which does not transform will cause the template to match correctly.
CPPUNIT_ASSERT_EQUAL (exist.getfilesize (), (dword) file_size;
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILESIZE (), FILESTATUSERROR);
}
Void testfileexist ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT (exist.fileexist ());
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT (! NOTEXIST.FILEEXIST ());
Void testfilemodifydatebasic ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& Filetime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (EXIST.GETFILEMODIFYDATE ());
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILEMODIFYDATE (), FILESTATUSERROR);
CPPUNIT_ASSERT_THROW (Notexist.SetFileModifyDate (& FileTime), FileStatuserror);
}
void testfilemodifydateequal ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
Filetime get = exist.getfilemodifydate ();
/ / Here, FileTime does not define Operator ==, so you can't use CPPUnit_assert_equal directly
CPPUNIT_ASSERT (COMPAREFILETIME (& GET, & FileTime) == 0);
}
}
Then we write a Filestatus class's skeleton that allows this test code to be compiled.
Class FileStatuserror
{};
Class Filestatus
{
PUBLIC:
FILESTATUS (Const std :: string & filename)
{}
DWord getFileSize () const
{
Return 0;
}
Bool fileexist () const
{
Return False;
}
void setfilemodifydate (const filetime *)
{
}
Filetime getfilemodifydate () const
{
Return filetime ();
}
Std :: string getFilename () const
{
""; "
}
}
The complete program is given below:
// UnitTest.cpp: Defines the entry point for the console application.
//
#include "cppUnit / testcase.h"
#include "cppunit / testResult.h"
#include "cppunit / textOutputter.h"
#include "cppUnit / testResultCollector.h"
#include "cppunit / testcaller.h"
#include "cppunit / extensions / helpermacros.h"
#include
#include
#include
Class FileStatuserror
{};
Class Filestatus
{
PUBLIC:
FILESTATUS (Const std :: string & filename)
{}
DWord getFileSize () const
{
Return 0;
}
Bool fileexist () const
{
Return False;
}
void setfilemodifydate (const filetime *)
{
}
Filetime getfilemodifydate () const
{
Return filetime ();
}
Std :: string getFilename () const
{
""; "
}
}
Class mytestcase: public cppUnit_ns :: testfixture
{
Std :: string mfilenameexist;
Std :: string mfilenamenotexist;
Std :: string mtestfolder;
ENUM DUMMY
{
FILE_SIZE = 1011
}
PUBLIC:
Virtual void setup ()
{
MTESTFOLDER = "C: JustFortest";
MfileNameexist = mtestfolder "exist.dat";
Mfilenamenotexist = mtestfolder "notexist.dat";
IF (getFileAttributes (mtestfolder.c_str ())! = invalid_file_attributes)
Throw std :: Exception ("Test Folder Already Exists);
IF (! Createdirectory (mtestfolder.c_str (), null)
Throw std :: Exception ("Cannot Create Folder);
Handle file = cretefile (mfilenameexist.c_str (), generic_read | generic_write,
0, NULL, CREATE_NEW, 0, NULL);
IF (file == invalid_handle_value)
Throw std :: Exception ("cannot create file");
CHAR BUFFER [file_size];
DWORD BYTESWRITTEN
IF (! Writefile (File, Buffer, File_Size, & Byteswritten, Null) ||
Byteswritten! = file_size)
{
CloseHandle (file);
Throw std :: Exception ("cannot write file");
}
CloseHandle (file);
}
Virtual Void Teardown ()
{
IF (! deletefile (mfilenameexist.c_str ())))
Throw std :: Exception ("cannot delete file");
IF (! RemoveDirectory (mtestfolder.c_str ())))
Throw std :: Exception ("Cannot Remove Folder";
void testorendgetname ()
{
Filestatus status (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), mfilenameexist;
}
Void testGetFilesize ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (exist.getfilesize (), (dword) file_size;
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILESIZE (), FILESTATUSERROR);
}
Void testfileexist ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT (exist.fileexist ());
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT (! NOTEXIST.FILEEXIST ());
}
Void testfilemodifydatebasic ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (EXIST.GETFILEMODIFYDATE ());
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILEMODIFYDATE (), FILESTATUSERROR);
CPPUNIT_ASSERT_THROW (Notexist.SetFileModifyDate (& FileTime), FileStatuserror);
}
void testfilemodifydateequal ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
Filetime get = exist.getfilemodifydate ();
CPPUNIT_ASSERT (COMPAREFILETIME (& GET, & FileTime) == 0);
}
}
int main ()
{
CPPUNIT_NS :: TestResult R;
CPPUNIT_NS :: TestResultCollector Result
R.AddListener (& result);
CPPUnit_ns :: testcaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
Testcase1.run (& r);
Testcase2.run (& r);
Testcase3.Run (& R);
Testcase4.Run (& R);
Testcase5.run (& r);
CPPUNIT_NS :: TextOutputter Out (& Result, std :: cout);
Out.write ();
Return 0;
}
The TestCaller here can convert the members of the class from TestFixTure to a TestCase. This code can be compiled, 5 tests after running, completely failed. This is the result of our expectations, so we further realize our function, and the code is completed is:
// UnitTest.cpp: Defines the entry point for the console application.
//
#include "cppUnit / testcase.h"
#include "cppunit / testResult.h"
#include "cppunit / textOutputter.h"
#include "cppUnit / testResultCollector.h"
#include "cppunit / testcaller.h"
#include "cppunit / extensions / helpermacros.h"
#include
#include
#include
#include
Class FileStatuserror
{};
Class Filestatus
{
Std :: string mfilename;
PUBLIC:
FileStatus (const st: string & filename): mfilename (filename)
{}
DWord getFileSize () const
{
DWORD FILESIZE = INVALID_FILE_SIZE;
Handle file = cretefile (mfilename.c_str (), generic_read, file_share_read | file_share_write,
NULL, OPEN_EXISTING, 0, NULL
IF (file! = invalid_handle_value)
{
FileSize = getFileSize (file, null);
CloseHandle (file);
IF (filesis == invalid_file_size)
Throw filestatuserror ();
Return FileSize;
}
Bool fileexist () const
{
Return getFileAttributes (mfilename.c_str ())! = invalid_file_attribute;
}
Void SetFileModifyDate (const filetime * filetime)
{
Bool result = false;
Handle file = cretefile (mfilename.c_str (), generic_read, file_share_read | file_share_write,
NULL, OPEN_EXISTING, 0, NULL
IF (file! = invalid_handle_value)
{
Result = setfiletime (file, null, null, filetime);
INT i = getLastError ();
CloseHandle (file);
}
IF (! result)
Throw filestatuserror ();
}
Filetime getfilemodifydate () const
{
Filetime Time;
Bool result = false;
Handle file = cretefile (mfilename.c_str (), generic_read, file_share_read | file_share_write,
NULL, OPEN_EXISTING, 0, NULL
IF (file! = invalid_handle_value)
{
Result = getFiletime (File, Null, Null, & Time);
CloseHandle (file);
}
IF (! result)
Throw filestatuserror ();
Return Time;
}
Std :: string getFilename () const
{
Return mfilename;
}
}
Class mytestcase: public cppUnit_ns :: testfixture
{
Std :: string mfilenameexist;
Std :: string mfilenamenotexist;
Std :: string mtestfolder;
ENUM DUMMY
{
FILE_SIZE = 1011
}
PUBLIC:
Virtual void setup ()
{
MTESTFOLDER = "C: JustFortest";
MfileNameexist = mtestfolder "exist.dat";
Mfilenamenotexist = mtestfolder "notexist.dat";
IF (getFileAttributes (mtestfolder.c_str ())! = invalid_file_attributes)
Throw std :: Exception ("Test Folder Already Exists);
IF (! Createdirectory (mtestfolder.c_str (), null)
Throw std :: Exception ("Cannot Create Folder);
Handle file = createfile (mfilenameexist.c_str (), generic_read | generic_write, 0, null, create_new, 0, null;
IF (file == invalid_handle_value)
Throw std :: Exception ("cannot create file");
CHAR BUFFER [file_size];
DWORD BYTESWRITTEN
IF (! Writefile (File, Buffer, File_Size, & Byteswritten, Null) ||
Byteswritten! = file_size)
{
CloseHandle (file);
Throw std :: Exception ("cannot write file");
}
CloseHandle (file);
}
Virtual Void Teardown ()
{
IF (! deletefile (mfilenameexist.c_str ())))
Throw std :: Exception ("cannot delete file");
IF (! RemoveDirectory (mtestfolder.c_str ())))
Throw std :: Exception ("Cannot Remove Folder";
}
void testorendgetname ()
{
Filestatus status (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), mfilenameexist;
}
Void testGetFilesize ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (exist.getfilesize (), (dword) file_size;
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILESIZE (), FILESTATUSERROR);
}
Void testfileexist ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT (exist.fileexist ());
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT (! NOTEXIST.FILEEXIST ());
}
Void testfilemodifydatebasic ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (EXIST.GETFILEMODIFYDATE ());
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (EXIST.GETFILEMODIFYDATE (), FILESTATUSERROR);
CPPUNIT_ASSERT_THROW (exist.setfilemodifydate;), filestatuserror);
}
Void testfilemodifydateequal () {
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
Filetime get = exist.getfilemodifydate ();
CPPUNIT_ASSERT (COMPAREFILETIME (& GET, & FileTime) == 0);
}
}
int main ()
{
CPPUNIT_NS :: TestResult R;
CPPUNIT_NS :: TestResultCollector Result
R.AddListener (& result);
CPPUnit_ns :: testcaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
Testcase1.run (& r);
Testcase2.run (& r);
Testcase3.Run (& R);
Testcase4.Run (& R);
Testcase5.run (& r);
CPPUNIT_NS :: TextOutputter Out (& Result, std :: cout);
Out.write ();
Return 0;
}
Run the test and find two errors:
1) TEST: TESTFILEMODIFYDATEBASIC (f) Line: 140 c: unittestUnitTest.cpp
Assertion failed
- Unexpected Exception Caught
2) TEST: TESTFILEMODIFYDATEEQUAL (f) Line: 150 C: UnitTestUnittest.cpp
Assertion failed
- Unexpected Exception Caught
Debugment found that in my setFileModifyDate, the file open mode is generic_read, only read permissions, naturally cannot be written. Replace this with generic_read | generic_write, run again, everything is OK!
In fact, there are still some problems with the test and implementation of the code. For example, the test case is not fine enough, some tests can continue to subdivide a few functions, so once the test is wrong, you can know the wrong location very accurately (Because the abnormal error is not known). However, it should be enough to explain how to test drive development should be sufficient. Vi. Test Set
CPPUnit_ns :: testcaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
CPPUNIT_NS :: TestCaller
Although this code is still uncomfortable, let the programmer will do this, it is really a waste. CPPUnit provides us with a number of mechanisms to avoid such waste. We can modify our test code as:
Class mytestcase: public cppUnit_ns :: testfixture
{
Std :: string mfilenameexist;
Std :: string mfilenamenotexist;
Std :: string mtestfolder;
ENUM DUMMY
{
FILE_SIZE = 1011
}
CPPUNIT_TEST_SUITE (MyTestCase);
CPPUNIT_TEST (TestCTORAAndgetName);
CPPUNIT_TEST (TestGetFileSize);
CPPUNIT_TEST (TESTFILEEXIST);
CPPUNIT_TEST (TestfileModifyDateBasic);
CPPUNIT_TEST (TESTFILEMODIFYDATEEQUAL);
CPPUNIT_TEST_SUITE_END ();
PUBLIC:
Virtual void setup ()
{
MTESTFOLDER = "C: JustFortest";
MfileNameexist = mtestfolder "exist.dat";
Mfilenamenotexist = mtestfolder "notexist.dat";
IF (getFileAttributes (mtestfolder.c_str ())! = invalid_file_attributes)
Throw std :: Exception ("Test Folder Already Exists);
IF (! Createdirectory (mtestfolder.c_str (), null)
Throw std :: Exception ("Cannot Create Folder);
Handle file = cretefile (mfilenameexist.c_str (), generic_read | generic_write,
0, NULL, CREATE_NEW, 0, NULL);
IF (file == invalid_handle_value)
Throw std :: Exception ("cannot create file");
CHAR BUFFER [file_size];
DWORD BYTESWRITTEN
IF (! Writefile (File, Buffer, File_Size, & Byteswritten, Null) ||
Byteswritten! = file_size)
{
CloseHandle (file);
Throw std :: Exception ("cannot write file");
}
CloseHandle (file);
}
Virtual Void Teardown ()
{
IF (! deletefile (mfilenameexist.c_str ())))
Throw std :: Exception ("cannot delete file");
IF (! RemoveDirectory (mtestfolder.c_str ())))
Throw std :: Exception ("Cannot Remove Folder";
}
void testorendgetname ()
{
Filestatus status (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (status.getfilename (), mfilenameexist;
}
Void testGetFilesize ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_EQUAL (exist.getfilesize (), (dword) file_size;
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILESIZE (), FILESTATUSERROR);
}
Void testfileexist ()
{
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT (exist.fileexist ());
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT (! NOTEXIST.FILEEXIST ());
}
Void testfilemodifydatebasic ()
{
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (EXIST.GETFILEMODIFYDATE ());
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
FILESTATUS NOTEXIST (MfileNameNotexist);
CPPUNIT_ASSERT_THROW (NOTEXIST.GETFILEMODIFYDATE (), FILESTATUSERROR);
CPPUNIT_ASSERT_THROW (Notexist.SetFileModifyDate (& FileTime), FileStatuserror);
}
Void testfilemodifydateequal () {
Filetime filetime;
GetSystemTimeAsFileTime (& FileTime);
FileStatus exist (mfilenameexist);
CPPUNIT_ASSERT_NO_THROW (& FileTiModifyDate);
Filetime get = exist.getfilemodifydate ();
CPPUNIT_ASSERT (COMPAREFILETIME (& GET, & FileTime) == 0);
}
}
CPPUNIT_TEST_SUITE_REGISTRAS (MyTestCase);
int main ()
{
CPPUNIT_NS :: TestResult R;
CPPUNIT_NS :: TestResultCollector Result
R.AddListener (& result);
CPPUNIT_NS :: TestFactoryRegistry :: getRegistry (). Maketest () -> Run (& r);
CPPUNIT_NS :: TextOutputter Out (& Result, std :: cout);
Out.write ();
Return 0;
}
here
CPPUNIT_TEST_SUITE (MyTestCase);
CPPUNIT_TEST (TestCTORAAndgetName);
CPPUNIT_TEST (TestGetFileSize);
CPPUNIT_TEST (TESTFILEEXIST);
CPPUNIT_TEST (TestfileModifyDateBasic);
CPPUNIT_TEST (TESTFILEMODIFYDATEEQUAL);
CPPUNIT_TEST_SUITE_END ();
The most important content is actually defined a function Suite, which returns a test set that contains all the test cases defined by CPPUnit_Test. CPPUNIT_TEST_SUITE_REGISTRATION Sign up in the global test tree by static registration, and finally through cppunit_ns :: testfactoryregistry :: getRegistry (). Maketest () Generates a test containing all test cases and runs. For details, please refer to the CPPUnit code.
VII. Section
This article briefly introduces the basic concepts of CPPUnit and test drive development, although CPPUnit has many other functions, such as the GUI-based test environment and test output connected to the compiler POST Build, and the extension of the test system Wait, but basically mastered the content of the test drive.
In addition, test-driven development can also check the errors of demand. In fact, I use GetFileTime and setFileTime as an example because there are some systems set, such as pressing, pressing, ..., after you set up a time, possible get back The time is different from it. This is actually a need for an error. Of course, because there is no such problem on my system, I will not have no disease. Specifically, you can refer to the introduction of these two functions in MSDN.