65.9K
CodeProject 正在变化。 阅读更多。
Home

eVC++ 应用程序的单元测试框架

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (12投票s)

2004年10月18日

CPOL

6分钟阅读

viewsIcon

88065

downloadIcon

283

eVC++ 应用程序的单元测试框架及其使用。

引言

首先,如果我的英语不好让您感到不适,请原谅。几个月前,我了解到 CPP Unit,这是一个 C++ 应用程序的单元测试框架。我去年刚大学毕业,对测试框架不太了解,所以使用 CPP Unit 对我来说是一次非常好的体验。由于我还在使用 Windows CE 进行编程,因此也有必要为那些应用程序编写测试用例。但是 CPP Unit 的问题在于,我无法为 Windows CE 编译它,因为它使用了一些 eVC++ 编译器不支持的 C++ 特性。我尝试寻找一个类似的 Windows CE 测试框架,但没有找到。因此,经过长时间的搜索,我决定为 Windows CE 应用程序编写自己的单元测试框架。这就是我最终的成果,我想与大家分享。

这是一个特别为 Windows CE 应用程序编写的单元测试框架。它提供了图形界面来选择和运行测试用例,并显示结果。如果用户需要,它还可以将运行的测试结果保存到文件中。

背景

在 WinCE 上使用 C++ 编程非常受限。它不支持模板、RTTI 和 C++ 的其他功能。CPP Unit 使用模板和 RTTI,但在 eVC++ 中不可用。这就是为什么我使用了大量的成员函数指针和回调来实现它。

使用框架

编译 WCEUnit 项目以生成特定平台的 WCEUnit.dll 文件。为了使用测试框架,测试用例项目必须与 WCEUnit.dll 链接。编写您的测试用例并将项目链接到 WCEUnit.dll。以下主题将讨论如何编写测试用例。

编写测试用例

当您编写测试类时,它应该从框架中定义的 CTestSuite 类派生。CTestSuite 类包含关于为该特定测试套件编写的测试用例的所有信息。应将单独的测试用例添加到测试套件中,如下例所示。下面示例中使用的宏定义在 WCEMacros.h 头文件中。这些宏封装了测试用例的添加机制。下面的代码显示了一个用于测试 CComplex 类的测试套件类。CComplex 类非常简单,实现了复杂的数字的基本运算,我将不详细介绍。

//TestComplex.h

#ifndef __TEST_COMPLEX_INCLUDED__
#define __TEST_COMPLEX_INCLUDED__

#include "..\WCEUnit\TestSuite.h"
#include "..\WCEUnit\WCEUnitMacros.h"
#include "Complex.h"

class CTestComplex : public CTestSuite
{
public:
    //Pass the name of the test class as parameter.
    WCEUNIT_TESTSUITE_INIT(CTestComplex);
    //Pass the name of the test case function as parameter.
    WCEUNIT_ADD_TESTCASE(testAdd);
    WCEUNIT_ADD_TESTCASE(testEqual);
    WCEUNIT_ADD_TESTCASE_EXCEPTION(testExcp, CUserException);
    WCEUNIT_TESTSUITE_END();

public:
    /***********************************************************
    The signature of test case function should be void (func)();
    ***********************************************************/
    void testAdd();
    void testEqual();
    void testException();
    void CleanUpTest();
    void InitializeTest(); 
private:
    CComplex*        m_p1;
    Ccomples*        m_p2;
    CComplex*        m_p3;
};
#endif //__TEST_COMPLEX_INCLUDED__

宏说明

  • WCEUNIT_TESTSUITE_INIT(testSuite)

    将测试套件类名传递给它。此函数定义了一个 CreateTestSuite() 函数的开始。此函数在 CTestSuite 类中定义为纯虚函数,用于创建测试用例列表。

  • WCEUNIT_ADD_TESTCASE(testCase)

    此宏将代码添加到 CreateTestSuite() 函数中,以添加一个测试用例函数。

  • WCEUNIT_ADD_TESTCASE_EXCEPTION(testCase, testException)

    此宏用于添加一种特殊类型的测试用例函数,该函数应该针对特定类型的异常进行测试。如果测试用例未抛出异常,则认为测试失败。

  • WCEUNIT_TESTSUITE_END()

    此宏结束 CreteTestSuite() 函数。

您可以在类的定义中看到 InitializeTest()CleanUpTest() 函数。这些函数在每次测试用例执行之前和之后被调用。从 UI 中,您可以选择这些函数如何被调用,即您希望这些函数为每个测试用例调用,还是只为某个测试套件类的所有测试用例调用一次。您可以通过在主对话框上选中或取消选中 **Init Once** 复选框来指定您的选择。

编写测试条件

在编写测试用例时,请使用 WCEUnitMacros.h 中定义的宏来编写测试条件。以下是用于编写测试条件的宏:

  • WCEUNIT_ASSERT(condition)

    如果 condition 的计算结果为 false,则断言并标记测试为失败。

  • WCEUNIT_ASSERT_FAIL(condition)

    这是上面宏的反向。如果您希望条件必须返回 false,请使用此宏来测试条件。

  • WCEUNIT_ASSERT_EQUALS(testValue, compValue)

    如果 testValuecompValue 不相等,则此宏断言。如果两个值不相等,则标记测试用例为失败。如果您正在使用用户定义的类对象进行比较,则该类必须重载 '==' 运算符。

  • WCEUNIT_DOUBLE_EQUALS(testValue, compValue)

    此宏与上面一个类似,但它假定 testValuecompValue 可以转换为 double 值。它将结果转换为 double 值然后进行比较。

  • WCEUNIT_DOUBLE_BETWEEN(testValue, minValue, maxValue)

    此宏测试 testValue 是否小于 maxValue 且大于 minValue。假定三个表达式值都被评估为 double。以下代码展示了上述宏的用法。

以下代码展示了上述宏在 CComplex 类的测试用例中的用法。

void CTestComplex::testAdd()
{
    CComplex temp;
    temp = *m_p1 + *m_p2;
    WCEUNIT_ASSERT(CComplex(30, 70) == temp);
}

void CTestComplex::testEqual()
{
    CComplex temp2;            //Below test should fail.
    WCEUNIT_ASSERT_FAIL(temp2 == *m_p3);

    CComplex temp1;            //Below test should pass.
    temp1 = *m_p1 + *m_p2;
    WCEUNIT_ASSERT_EQUALS(temp1, *m_p3);

    //To check the equality of the real and imaginary members.
    WCEUNIT_DOUBLE_EQUALS(temp1.GetReal(), m_p3->GetReal());
    WCEUNIT_DOUBLE_EQUALS(temp1.GetImaginary(), m_p3->GetImaginary());
}

void CTestComplex::testException()
{
    //This fuction is only to demonstrate the exception test.
    //It throws CUserException. This test will fail as the expected exception
    //is CFileException.

    CUserException e;
    THROW(&e);
}

void CTestComplex::InitializeTest()
{
    m_p1 = new CComplex(10, 20);
    m_p2 = new CComplex(20, 50);
    m_p3 = new CComplex(30, 70);
}

void CTestComplex::CleanUpTest()
{
    delete m_p1;
    delete m_p2;
    delete m_p3;
}

运行测试用例

CTestRunner 类负责运行测试用例并获取测试结果。要运行您编写的测试用例,请创建 CTestRunner 类的实例。还要创建所有测试套件类的实例,并将每个实例的地址传递给 CTestRunner 类的 AddTestSuite() 函数。然后调用 CTestRunnerStart() 函数。以下代码显示了如何运行测试用例。

BOOL CTestComplexApp::InitInstance()
{
    //Create the instance of CTestRunner class.
    CTestRunner obj;
    //Create the instance of CTestComplex test suite class.
    CTestComplex test1;

    //Pass the address of CTestComplex instance to the AddTestSuite() function.
    obj.AddTestSuite(&test1);

    //Sart the WCEUnit dialog to run the test cases.
    obj.Start();
    return FALSE;
}

图形用户界面

WCEUnit/wceunit.jpg

上图显示了主对话框。要选择要运行的测试用例,请单击 **Select** 按钮,将出现一个新对话框,其中显示了您编写的测试用例的树状视图。您可以选择单个测试用例、测试套件或 **All Tests**。如果您想运行某个测试套件的所有测试用例,请选择该测试套件;如果您想运行所有测试套件的所有测试用例,请选择根节点 **All Tests**。 **Init once** 复选框用于选择 InitializeTest()CleanUpTest() 的调用方式。如果选中,则对于每个测试套件,IntializeTest()CleanUpTest() 分别在所有测试用例执行之前和之后仅调用一次。如果未选中,则对于每个测试用例都会调用这两个函数。单击 **Run** 按钮来运行选定的测试用例。结果显示在列表框中。如果您想查看更多信息,只需单击结果项,您将看到详细的结果。如果您想将测试结果保存到文本文件中,请选中 **Make log** 复选框,将创建一个名为 \\WCEUnitLog.txt 的文件,其中包含详细的测试结果信息。

关注点

在此项目开发过程中,我学到了很多关于 C++ 中成员函数指针的知识。它们非常强大,能做很多超出您想象的事情。也许下次,我会尝试写一些关于成员函数指针的文章。

© . All rights reserved.