如果私有变量发生了变化,如何进行单元测试

时间:2017-08-15 17:26:23

标签: c++ unit-testing testing mocking googletest

假设我在C ++中有这个类:

class ExampleClass{
private:
    int example_var;
public:
    void exampleMethod(){
         example_var = other_value; // other value will be always different
    }
}

我如何进行单元测试exampleMethod()?我想做这样的事情:

void testExampleMethod(){
    ExampleClass obj;
    int before_call_value = obj.example_var;
    obj.exampleMethod();
    int after_call_value = obj.example_var;
    ASSERT_NOT_EQUALS(before_call_value, after_call_value);
}

example_var是私密的。

那么,进行单元测试的正确方法是什么?如何测试私有example_var是否已更改?

5 个答案:

答案 0 :(得分:10)

简短回答:不要这样做。

您的测试应仅针对公共接口进行测试。让我试着用一些代码来解释:

class Adder {
    int a,b;
public:
    Adder() : a(0),b(0) {}
    void set(int x,int y) { a=x;b=y; }
    int get()             { return a+b; }
};

和测试(假设我们有权访问ab):

void testAdder(){
    Adder add;
    int a = 1;
    int b = 2;
    add.set(a,b);
    ASSERT_EQUALS(add.a,a);
    ASSERT_EQUALS(add.b,b);
    ASSERT_EQUALS(add.get(),a+b);
}

假设您已经分发了代码并且有人正在使用它。他想继续使用它,但抱怨内存消耗过多。在保持相同的公共接口的同时解决此问题很简单:

class Adder {
    int c;
public:
    Adder() : c(0) {}
    void set(int x,int y) { c = x+y; }
    int get()             { return c; }
};

这很容易,但测试会失败:(

结论:测试私有实现细节会破坏测试的目的,因为每次修改代码时,您都可能需要“修复”测试。

答案 1 :(得分:4)

测试私有变量/方法是不好的方法。但如果你需要,有很多选择:

  1. 您可以将您的测试类作为ExampleClass的朋友

  2. 您可以使用moc对象

  3. 获取信息

答案 2 :(得分:2)

如果您想访问example_val,您可以执行以下两项操作之一。第一种方法是将testExampleMethod()作为朋友方法,如下所示:

class ExampleClass{
private:
    int example_var;
public:
    void exampleMethod(){
         example_var = other_value; // other value will be always different
    }
    friend void testExampleMethod(); //Now you can use the function as is.
}

另一方面,您可以在ExampleClass添加一个getter来访问变量,例如:

class ExampleClass{
private:
    int example_var;
public:
    void exampleMethod(){
         example_var = other_value; // other value will be always different
    }
    inline void getExampleVar() const { return example_var; }
}

然后将testExampleMethod()更改为:

void testExampleMethod(){
    ExampleClass obj;
    int before_call_value = obj.getExampleVar();
    obj.exampleMethod();
    int after_call_value = obj.getExampleVar();
    ASSERT_NOT_EQUALS(before_call_value, after_call_value);
}

我会诚实地使用第二种方法,因为通常不建议访问类的私有变量。

答案 3 :(得分:2)

您只需为要获得的get变量实现private函数。

class ExampleClass{
private:
    int example_var;
public:
    void exampleMethod(){
         example_var = other_value; // other value will be always different
    }

    int GetExampleVar(){
         return example_var;
    }
}

并称之为

void testExampleMethod(){
    ExampleClass obj;
    int before_call_value = obj.GetExampleVar();
    obj.exampleMethod();
    int after_call_value = obj.GetExampleVar();
    ASSERT_NOT_EQUALS(before_call_value, after_call_value);
}

或者使testExampleMethod friend function(朋友函数可以访问朋友类的私有变量,即使它不是它的方法)。

class ExampleClass{
private:
    int example_var;
public:
    void exampleMethod(){
         example_var = other_value; // other value will be always different
    }

    friend void testExampleMethod();
}

在我看来,第一个示例会更合适,但如果您无法修改ExampleClass,则可以关闭gcc - -fno-access-control的访问控制。

答案 4 :(得分:2)

我能想到的一些选择:

1)使测试代码成为该类的friend。这样它就可以访问私人会员。

2)在#ifdef Testing指令下的类中添加一个getter,该指令仅在构建测试版本时被定义(或者在该宏下放置public:并在private:中放置#else {1}}分支)。

3)#define private public在构建测试时(不,不是真的)。​​

4)在构建要测试的版本时使用gcc的-fno-access-control标志,以便所有内容都是公开的(如果您使用的是gcc)。

5)只需从课堂外部放弃测试,而是将相关static_assert s / assert添加到类本身以测试不变量。

6)不要。坚持测试公共界面。

希望有所帮助: - )