单元测试类构造函数

时间:2012-11-19 05:21:19

标签: c++ unit-testing class testing

在C ++中如何测试类构造函数?例如:

Class myClass{
    int a;

public:
    myClass(); //Constructor
    void reset(); //resets a to 0;

};

//Constructor defined to initialize a to 0
myClass::myClass(){
    reset();
}

//reset sets a to 0
void myClass::reset(){
    a = 0;
}

我如何测试myClass()构造函数?我无法访问私有数据成员,所以说重置是否有效然后构造函数工作是否有效?

4 个答案:

答案 0 :(得分:6)

我打算将你的问题改为:我如何测试我的类的属性,这些属性不能直接从我的测试中观察到,因为它们是受保护的还是私有的?以下是我通常会考虑的顺序中的几种可能性:

  • 使用assert()将测试的检查部分移动到类中。如果要测试的是构造函数已经成功建立了一些复杂的不变量,那么你可以在构造函数的末尾放置一个assert()来验证该不变量。然后你所要做的就是调用构造函数 - 构造函数中的断言执行测试本来会做的实际检查。如果您在编写代码时习惯性地添加断言,那么断言已经存在(如果断言使您的调试构建太慢,请使用分析器来查明那些实际上存在问题的断言)。

  • 将要测试的复杂代码提取到第二个类中。然后,您可以通过其公共接口测试第二个类。即使不考虑可测试性,当提取第二类改进代码时,此选项也很有吸引力。

  • 将您的代码设计更改为更可测试的其他方式。同样,即使不考虑可测试性,当改变是一种改进时,这也很有吸引力。

  • 战略撤退。在所有其他条件相同的情况下单独测试代码是好的,但是没有法律规定所有代码必须孤立地进行测试。有时候正确的答案是让测试代码作为测试其他东西的副作用。毕竟,对于该类的所有其他测试都将调用构造函数,因此如果构造函数出现问题,则可能会导致其他测试之一失败。以这种方式覆盖所有路径可能更难,并且当您遇到失败时,追踪失败原因会更麻烦,因为现在您不知道问题是构造函数还是正在测试的其他东西。这可能是也可能不是什么大不了的事。考虑到你可以在那个时间使用的其他内容以及这个测试实际发现错误的可能性,是否真的值得单独测试这个代码?代码审查会是一种更有用的方式来花时间吗?是否还有其他更有用的事情呢?

如果你真的必须测试一些无法用assert()测试的东西,并且没有可接受的重构来提高可测试性,那么仍然有一些选择。我从来没有必要使用它们进行测试,但它们是:

  • 使用好友声明,让您的测试可以访问您班级的私人字段。现在,每个类都需要为需要访问的测试维护一个友元声明列表。这可能是一项值得维护的苦差事。

  • 维护一个单独的界面供测试使用。有一组方法可以提供您需要的访问权限,其名称前缀如“testOnly”。所以在你的情况下,它将是testOnlyGetA()。只需要从测试中调用这些方法,您就必须遵守规则,现在需要维护比以前更大的界面。

  • 抓住您的鼻子并在测试文件中执行#define private public,然后再添加您要测试的标题。

答案 1 :(得分:0)

UPD。对不起,被误解了。

您可以将朋友测试功能添加到类或类成员测试功能(这更好地测试实现细节,但由于测试框架限制有时是不可能的)

答案 2 :(得分:0)

您可以在课程中添加一个提升测试用例:

Class myClass{
    private:
        int a;

    public:
        myClass(); //Constructor
        void reset(); //resets a to 0;
        void test_a_reset() {
            BOOST_CHECK_EQUAL(a, 0);
        }

};

我不确定你是如何进行测试的。这可能不是你想要的。

答案 3 :(得分:-1)

您可以使用原始类的相同内存布局声明测试类,但所有成员都是公共的。

void testMyClassConstructor()
{
    class myClassPublic
    {
    public:
        int a;
        myClassPublic();
        void reset();
    };

    typedef union
    {
        myClass* original;
        myClassPublic* testView;
    } u_myClass;

    myClass testInstance;
    u_myClass testUnion;
    testUnion.original = &testInstance;

    assert(testUnion.testView->a == 0);
}

如果您无法更改测试类的界面,则在白盒测试用例中这很好。 但是,请记住,对原始类的内存布局的任何更改都将破坏单元测试。