单元测试 - 设置私人成员以获得所需的对象状态



我正在对单元测试进行第一步,并且在封装方面存在问题。我的班级有一些私人成员变量,客户不应该可见,但是为了使我将对象放在要在下面进行测试的状态,我需要设置那些私人变量。

说我有这样的代码:

Class Foo {
public:
  int action() ;  
private:
  int state ;
} ;
int Foo::action()
{
  if(this->state == 1)
    return 1 ;
  else
    return 0 ;
}

所以现在我想测试Foo::action(),但是我需要能够设置Foo::state以在不同方案下检查功能。一种解决方案是测试代码中的邪恶" define private public"。但是有更优雅的东西吗?我想强调的是,Foo::state是客户不应该访问的变量,因此我不想声明任何公共设置。

编辑:

我现在认为,扩展要在测试代码中测试的类,并在该类别中包括设置器将起作用,只要我将私人变量更改为受保护。但这是一个"仅一代"的解决方案,仍然感觉像是一种黑客而不是适当的方法。

编辑2:

在阅读了答案和评论后(特别感谢Lieven和Ap。),我相信我现在要测试的实际课程(不是我提供的简单示例)只是做得太多了,对我的答案的答案问题是将其某些逻辑移至另一个类别。

  1. 使用公共接口设置状态。
  2. 状态是冗余如果您无法通过公共接口设置为

选项2是自我解释的,很可能不适用于您的案件,因此您可以通过类的公共接口设置状态。

正如您已经提到的那样,这是可能的,但是需要大量代码才能达到正确的状态。这本身可能表明您的班级目前正在做很多事情,现在该将班级的部分重构为较小的可测试课程了。

从不要测试私人方法

如果您发现需要测试私人方法,那么您正在做 还有其他问题。可以这么说,有一个"上游"问题。你 由于以前的其他错误,已经解决了这个问题 这个流程。尝试隔离那是什么,然后删除它 而不是弯曲测试以沿着一条痛苦的道路 测试中的脆性。

和单位测试私人成员

我建议不要单位测试私人方法。因为他们 私人,可以在任何可能的(或不可想象的?)中更改它们。 每个版本之间的方式。如果给定的私人方法非常关键 对于您认为应得的班级的班级操作, 然后,可能是时候将其重构为受保护或 公共方法

关于此的常见报价是

您永远不要触摸您的私人

如果您的测试类称为myTestClass,则将mytestClass添加为类Foo中的朋友,以便能够访问其私有成员变量。

Class Foo {
public:
    int action();  
private:
    int state;
    friend class MyTestClass;
};

您应该有一些 public ly(或 protected ly&quort")可访问机制,以更改私有变量state的价值。为简单起见,假设这是一种方法Foo::setState(int inState)。在单元测试中使用它来更改状态,从而测试Foo::action()方法。这样可以确保任何未来的实施更改都不会影响单位测试(除非" API" Foo::setState()更改 - 当然,在这种情况下,您必须更改单位测试)。

如果您做具有更改state的机制,则表示最终用户或调用代码也无法更改它,因此,您无需进行测试(也许是使state多余,但我不知道)。

如果私人变量更改"间接"通过其他代码,您必须在单元测试中执行相同的代码。您始终可以将外部可见的任何方法追溯到外部馈送给代码的输入。基本上是关键是,在单位测试中,您必须将相同的输入馈送到"真实"中的代码中。方案,然后测试是否应响应。

如下评论所讨论的,如果"路径"从要测试的代码的输入到长,代码/测试可能必须分解为较小的模块或中间点。要详细说明,将代码流视为:

Input -> A -> B -> C -> Output
// A, B, C are intermediate execution points which are not "publicly accessible".

在上述情况下,您所能做的就是

给定的Input,检查Output是否正确。

相反,至少将中间的 ABC暴露在单位测试中是一件好事,这样您现在可以将测试分解为:

给定的Input,检查A是否正确。

给定的A,检查B是否正确。

给定的B,检查C是否正确。

给定的C,检查Output是否正确。

您可以想象,如果测试失败,则更容易弄清楚失败的内容,从而修复它。

最新更新