【问题标题】:How to test member-wise equality operator?如何测试成员平等运算符?
【发布时间】:2020-09-18 03:46:25
【问题描述】:

我有一个由三个成员 { xx, xy, yy } 和一个重载的 == 运算符组成的结构,该运算符按成员测试左右表达式的相应成员是否在某个精度范围内相等,或者两者都是 NaN s。相当琐碎。

对于我的测试用例,我想针对一个错字情况,我错误地比较了错误的成员。也许,我将左侧表达式中的xx 与右侧表达式中的xy 进行比较。也许,我根本忘了比较yy

由于我使用的是 C++20,我不知道是否有可能构建 == 运算符正确性的编译时证明(如果我应该这样做的话)。试图以通常的方式解决这个问题,我发现自己列举了所有可能的排列:

EXPECT_EQ(C{1, 2, 3}, C{1, 2, 3});
EXPECT_NE(C{1, 2, 3}, C{1, 3, 2});
EXPECT_NE(C{1, 2, 3}, C{2, 1, 3});
EXPECT_NE(C{1, 2, 3}, C{2, 3, 1});
EXPECT_NE(C{1, 2, 3}, C{3, 1, 2});
EXPECT_NE(C{1, 2, 3}, C{3, 2, 1});
EXPECT_NE(C{1, 2, 3}, C{1, 2, nan});
EXPECT_NE(C{1, 2, 3}, C{1, nan, 3});
EXPECT_NE(C{1, 2, 3}, C{nan, 2, 3});
// ...

EXPECT_NE(C{1, 3, 2}, C{1, 2, 3});
EXPECT_EQ(C{1, 3, 2}, C{1, 3, 2});
// ...

这样的代码很丑,如果我用嵌套循环复制同样的代码:

for (T lxx = 1; lxx <= 3; lxx += 1) {
  for (T rxx = 1; rxx <= 3; rxx += 1) {
    for (T lxy = 1; lxy <= 3; lxy += 1) {
      for (T rxy = 1; rxy <= 3; rxy += 1) {
        // ...

似乎我在测试中重新实现了相等运算符,这错过了测试的重点。

如何正确执行此操作?我是否错过了一些边缘情况,也许这会简化它?如果我在一个结构中有四个成员并且不希望测试用例代码爆炸,如何扩展此类测试?

【问题讨论】:

  • 除非检查所有可能的输入,否则无法证明函数的正确性。
  • @cigien 我同意测试。但除此之外,可以使用 curry-howard 同构和证明助手 (Coq) 来证明代码的正确性而无需测试。
  • 在测试中总有一点需要人工验证。由于许多测试通常取决于等式运算符的有效性,因此该等式运算符最终无法使用通常的行为测试技术进行测试。在测试中编写或复制粘贴相等运算符的主体不是一个坏主意,检查两次,查看输入。至少你的测试会发现回归。

标签: c++ unit-testing testing c++20


【解决方案1】:

单元测试不是要证明正确性,而是要对代码的行为有信心。

假设您的操作员是这样定义的:

bool operator==(T const& lhs, T const& rhs) {
    return (lhs.xx - rhs.xx) <= epsilon && (lhs.xy - rhs.xy) <= epsilon && (lhs.yy - rhs.yy) <= epsilon;
}

尽可能多地测试输入是没有意义的。该功能非常琐碎,您应该关注可能出现的问题。

例如,您说您想确保没有可能使函数比较错误成员的拼写错误。好吧,像你写的第一个测试一样,EXPECT_EQ(C{1, 2, 3}, C{1, 2, 3}),就是你所需要的。如果每个成员的值至少相差 epsilon,那么当您的函数比较错误的成员时,测试通过的可能性很小。

顺便说一句,你提到你的相等运算符检查对应的成员是否在某个精度内或两个 NaN。我认为您不希望 NaN 比较相等。根据定义,它们不是数字,因此没有为它们定义相等性。这就是 IEEE 754 NaN 从不比较相等的原因,即使它们的二进制表示相同。

如果你不这样做,那么在这里用 NaN 进行测试是没用的,因为 NaN 会传播,并且再次,不要与任何东西进行比较。如果你这样做了,那么你就为它们编写了一些你想要测试的特殊情况,但是一两个相等测试就足够了。

您可能要检查的是 epsilon(如果您实际使用的)在不同情况下是否具有合理的值。这也伴随着传递性(或缺乏传递性)的问题,但这是您必须决定的行为。

【讨论】:

    猜你喜欢
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多