如何测试成员相等运算符?



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

对于我的测试用例,我想针对拼写错误的情况,即我错误地比较了错误的成员。也许,我将左手表情的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) {
// ...

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

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

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

假设您的运算符定义如下:

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(如果这是您实际使用的(在不同情况下是否具有合理的值。这也伴随着传递性(或缺乏传递性(的问题,但这是您必须决定的行为。

最新更新