为什么assertEquals()的参数顺序是(预期,实际)?

135 投票
9 回答
57000 浏览
提问于 2025-04-15 20:10

为什么很多像assertEquals()这样的函数,把期望的值放在第一个参数,而把实际的值放在第二个参数呢?这让我觉得有点不太符合直觉,难道这样排列有什么特别的原因吗?

9 个回答

20

assertEqual()的一个隐含目的就是为了给人类读者演示代码。

简单的函数调用可以展示左边是期望的返回值,而右边是函数调用

    y = f(x)

按照这个约定,函数的自我测试演示可以是这样的:

    assertEqual(y, f(x))

顺序是(期望值,实际值)。

下面是一个关于sum()函数的演示,左边是一个字面上的期望返回值,右边是一个计算实际返回值的函数调用:

    assertEqual(15, sum((1,2,3,4,5)))

同样,这里有一个表达式的演示。它也遵循(期望,实际)的自然顺序:

    assertEqual(4, 2 + 2)

另一个原因是风格上的。如果你喜欢对齐,期望的参数放在左边更好,因为它通常比较短:

assertEqual(42, 2 * 3 * 7)
assertEqual(42, (1 << 1) + (1 << 3) + (1 << 5))
assertEqual(42, int('110', int('110', 2)))

我怀疑这可以解开@ChrisPovirk提到的关于Kent Beck所说的“期望值放在前面让它们更易读”的谜团。

感谢Andrew WeimholtGanesh Parameswaran提供的这些公式。

30

因为作者有50%的机会能猜到你的想法。

还有其他的负担。

assertWhatever(explanation, expected, actual)

而这个解释,实际上是你已经知道的部分,它和你预期的结果是相符的,这些都是你知道的东西,而不是你在写代码时不知道的实际情况。

56

这是Kent Beck的一个回答,他是JUnit的共同创始人(可能这个约定就是从这里来的,因为他之前的SUnit似乎没有包含assertEquals):

把一堆assertEquals排成一行。把预期值放在前面会让它们看起来更好。

在我最初的回答中,我说我不太理解这个。以下是我在测试中经常看到的内容:

assertEquals(12345, user.getId());
assertEquals("kent", user.getUsername());
assertEquals("Kent Beck", user.getName());

我觉得把实际值放在前面会更好。这样可以把重复的代码放在一起,方便对齐我们正在测试的值的方法调用:

assertEquals(user.getId(), 12345);
assertEquals(user.getUsername(), "kent");
assertEquals(user.getName(), "Kent Beck");

(我还有其他原因喜欢这种顺序,但在这个问题中,Kent的理由似乎就是答案。)

不过,Bob Stein在下面有一个评论(和这个类似),提到了一些“预期值放在前面”的好处。主要的想法是,预期值通常比较短——往往是字面量或变量/字段,而不是可能复杂的方法调用。因此:

  • 一眼就能更容易识别预期值和实际值。
  • 可以用少量的额外空格来对齐它们(如果你喜欢这样做,尽管我在我能轻易找到的最早的JUnit提交中没有看到这种用法):
assertEquals(12345,       user.getId());
assertEquals("kent",      user.getUsername());
assertEquals("Kent Beck", user.getName());

谢谢你,Bob!

撰写回答