如何在单元测试中访问私有成员?

时间:2016-02-28 12:22:27

标签: c++ unit-testing

在开发单元测试时,访问私有成员以检查类的内部状态可能是必要的。有时getter和setter函数不可用,有时它们不公开。

处理它的第一种方法,编写预处理器定义写publis而不是private和protected。

#define protected public
#define private public

第二种方法是让测试类成为类的朋友。

class test_foo {
};

class foo {
private:
  int mem;

  friend class test_foo;
};

第三种方法是为测试创建公共接口。

class foo {

#if defined FOO_UNIT_TEST
public:
  int get_mem() const;
#endif

private:
  int mem;
};

除了这些方法之外还有其他方法吗?每种方法都有利有弊。哪一个可以被认为是最佳实践?

感谢。

3 个答案:

答案 0 :(得分:6)

我认为这三种解决方案都很难看。我想说最好的做法是不在单元测试中检查你的类的内部状态,而不是仅仅为单元测试公开方法。这样做违反了TDD的原则。

良好的单元测试不会对内部状态做出任何假设,如果类实现完全更改,则无需修改即可运行。

为什么检查内部状态是必要的?也许你的设计问题可以通过重新设计而不是黑客来解决。你有更全面的例子说明你想要实现的目标吗?

答案 1 :(得分:2)

这就是为什么我觉得测试这个细节的课程从根本上说是一个坏主意。

它破坏了封装。

测试有效,因为它是从规范的角度对单元功能的冷静评估,而不是编程。从程序员的角度编写测试时,你可以打败这个目的。

谁将编写单元测试?

如果是编写课程的人,那么他已经对算法的工作原理以及应该在哪里的值有了自己的想法。他可能会编写测试来适应他引入的大部分错误,从而使测试与代码一样错误,并且更糟糕的是,给错误的代码免费传递。

如果是没有写过课程的人,他们怎么知道私人成员应该和不应该包含什么?那个人必须检查内部算法,以便发现私人成员在什么点需要什么值。它们也可能受到代码所代表的内容的影响,而不是规范所要求的内容。他们也可能会将代码中的错误引入测试,为他们提供免费通行证。

最重要的是,我认为从实施者的角度来测试类本质上是有缺陷的,并且邀请测试本身就像他们测试的代码一样错误。

让第二副眼睛查看/共同开发代码是一件好事,但对于编码阶段而言,这不是测试。

测试应该从规范的角度设计,它们应该是打破合同。它们不应该是您在算法中发现错误的能力。如果测试失败,这就是程序员的工作。测试人员的工作是专注于基于外部刺激的因果。他们应该问的问题是"班级是否做了宣传的做法?"不是"代码是否正常运行?"。

这并不是说程序员不应该考虑测试代码。可以设计类以使其合同更加可测试。但是编写测试的人不应该知道或关心 类如何执行它所做的事情,只是根据规范正确地执行它。

在测试时,规范是王道,而不是实施

因此,当您针对规范进行实施时,我认为测试是有效的。如果您开始查看实现,那么您就开始了解一个人如何实现应该如何解决实施应该如何工作以及他们冒风险的另一个想法要么将自己的实现错误引入测试,要么加强原始程序员的错误。

答案 2 :(得分:1)

没有"最佳实践"在这种事情。只有不同的主观意见。

您的第一个选项不是一个好习惯,因为使用预处理器重新定义语言关键字被指定为给出未定义的行为。可能引入未定义行为的测试用例可能会因为与被测试类的特征完全无关的原因而失败或(甚至更糟)通过。

在这三个中,我可能会鼓励第二种方法(进行单元测试的朋友类)。这样,测试可以以不依赖于被测试类的任何特定功能的方式实现,但可以检查它喜欢的任何内容。

第三个选项具有与类的其他成员函数冲突或从基类继承的潜在缺点。我记得有一个同事遇到类似技术的问题,当测试函数碰巧与基类中声明的虚函数具有相同的签名时(其中一个函数使用具有多个不同含义的英文单词命名)因此,测试功能导致其他明显不相关的测试失败。

最好尽可能地设计你的课程,因此不必检查课程的内部状态。但是,我意识到有一些V& V制度,有必要提供一个类别的单独证据。成员函数是正确实现的 - 如果不检查类私有数据就很难实现。