2017-08-15 70 views
8

比方说,我有这个类在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是否已更改?

+1

你不能为'example_var'实现'get'函数吗? –

+2

单元测试真的是主观吗?公共接口的行为?我不确定白盒测试是否值得这个努力。 – user0042

+0

By测试可变行为,这种行为是通过改变这个变量产生的,与单元测试者交朋友,或者按照我的偏好添加一个getter。 – user4581301

回答

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; } 
}; 

这很简单,但会导致测试失败:(

结论:测试私有实现细节打败测试的目的,因为每个当你修改代码时,你可能还需要“修复”测试。

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. 
} 

在另一方面,你可以只添加一个getter您ExampleClass访问变量,如下列:

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); 
} 

我就老老实实用第二种方法,因为访问类的私有变量是根完全不建议。

4

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

  1. 你可以让你的测试类作为ExampleClass朋友

  2. 可以使用MOC对象抓取信息

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); 
} 

或者使testExampleMethodfriend 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

+2

添加getter更改公共API:它公开的状态之前被隐藏起来,而且可能因为一个很好的原因而被隐藏起来。 –

+0

当然,它只是一个opputurnity。如果他必须保持隐藏状态,他会选择另一个。 –

2

我能想到的有几个选项:

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

2)添加一个getter到下,只有建立了测试版的时候被定义的#ifdef Testing指令是类(或把public:,宏观和中#else分支private:)下。

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

4)构建要测试的版本时使用gcc的-fno-access-control标志,以便一切都公开(如果您使用的是gcc)。 5)只要放弃在课堂上进行的外部测试,而是将相关的static_assert s/assert s添加到类本身以测试不变量。

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

希望帮助:-)

相关问题