技术开发 频道

用cpp做C单元测试

    编写测试用例

    一旦我们知道我们要测什么之后,我们就可以写测试用例了。我们能够执行所有的我们需要的操作:使用普通库函数,第三方库,win32api库函数,或简单使用c++内部操作

    有时候,我们需要调用外部辅助文件或者数据库,比较外部文件和内部数据是否一致。

    检测一个条件就使用
        CPPUNIT_ASSERT(condition):如果为false就抛出异常

        CPPUNIT_ASSERT_MESSAGE(message, condition): 如果为false就抛出制定的信息。

        CPPUNIT_ASSERT_EQUAL(expected,current): 检测期望值

        CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,current): 当比较值不相等时候抛出的制定的信息。

        CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,current,delta): 带精度的比较

        下面是测试loadTest的例子,          //
        // These are correct values stored in auxiliar file
        //
        #define AUX_FILENAME "ok_data.dat"
        #define FILE_NUMBER 19
        #define FILE_STRING "this is correct text stored in auxiliar file"
        void DiskDataTestCase::loadTest()
        {
            // convert from relative to absolute path
            TCHAR absoluteFilename[MAX_PATH];
            DWORD size = MAX_PATH;
            strcpy(absoluteFilename, AUX_FILENAME);
            CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &size) );
            // executes action
            CPPUNIT_ASSERT( fixture->load(absoluteFilename) );
            // ...and check results with assertions
            LPDATA loadedData = fixture->getData();
            CPPUNIT_ASSERT(loadedData != NULL);
            CPPUNIT_ASSERT_EQUAL(FILE_NUMBER, loadedData->number);
            CPPUNIT_ASSERT( 0 == strcmp(FILE_STRING,
            fixture->getData()->string) );
        }


    在这个case我们得到四个可能的错误:          load method's return value
        getData method's return value
        number structure member's value
        string structure member's value

    第二个用例也是相似的。但是困难点,我们需要使用已知的数据来填充fixture,把它存在磁盘临时文件里,然后打开两个文件(新的和辅助文件),读并比较内容,两者如一致就正确          void DiskDataTestCase::storeTest()
        {
            DATA d;
            DWORD tmpSize, auxSize;
            BYTE *tmpBuff, *auxBuff;
            TCHAR absoluteFilename[MAX_PATH];
            DWORD size = MAX_PATH;
            // configures structure with known data
            d.number = FILE_NUMBER;
            strcpy(d.string, FILE_STRING);
            // convert from relative to absolute path
            strcpy(absoluteFilename, AUX_FILENAME);
            CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &size) );
            // executes action
            fixture->setData(&d);
            CPPUNIT_ASSERT( fixture->store("data.tmp") );
            // Read both files contents and check results
            // ReadAllFileInMemory is an auxiliar function which allocates a buffer
            // and save all file content inside it. Caller should release the buffer.
            tmpSize = ReadAllFileInMemory("data.tmp", tmpBuff);
            auxSize = ReadAllFileInMemory(absoluteFilename, auxBuff);
            // files must exist
            CPPUNIT_ASSERT_MESSAGE("New file doesn't exists?", tmpSize > 0);
            CPPUNIT_ASSERT_MESSAGE("Aux file doesn't exists?", auxSize > 0);
            // sizes must be valid
            CPPUNIT_ASSERT(tmpSize != 0xFFFFFFFF);
            CPPUNIT_ASSERT(auxSize != 0xFFFFFFFF);
            // buffers must be valid
            CPPUNIT_ASSERT(tmpBuff != NULL);
            CPPUNIT_ASSERT(auxBuff != NULL);
            // both file's sizes must be the same as DATA's size
            CPPUNIT_ASSERT_EQUAL((DWORD) sizeof(DATA), tmpSize);
            CPPUNIT_ASSERT_EQUAL(auxSize, tmpSize);
            // both files content must be the same
            CPPUNIT_ASSERT( 0 == memcmp(tmpBuff, auxBuff, sizeof(DATA)) );
            delete [] tmpBuff;
            delete [] auxBuff;
            ::DeleteFile("data.tmp");
        }


    调用用户接口
    最后,我们看看用一个mfc 对话框(TestRunner.dll)用来说明。

    我们需要在我们的初始化函数中做如下初始化          #include <cppunit/ui/mfc/TestRunner.h>
        #include <cppunit/extensions/TestFactoryRegistry.h>
        BOOL CMy_TestsApp::InitInstance()
        {
            ....
            // declare a test runner, fill it with our registered tests and run them
            CppUnit::MfcUi::TestRunner runner;
            runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );
            runner.run();
            return TRUE;
        }


    只要定义一个test的实例,然后注册所有用例,在跑case。
    每发现一个错误时9比如发现内部数据和外部数据不同我们就创建一个异常,使用 CPPUNIT_FAIL(message) 来显示异常信息。

0
相关文章