为什么这么多assertEquals()或类似的函数将期望值作为第一个参数而实际的函数作为第二个参数?
这对我来说似乎是违反直觉的,所以这种不寻常的订单有什么特别的原因吗?
bma*_*ies 26
因为作者有50%的机会匹配你的直觉.
因为其他超负荷
assertWhatever(explanation, expected, actual)
Run Code Online (Sandbox Code Playgroud)
而这个解释是你所知道的一部分,与预期的一致,就是你所知道的,而不是你在编写代码时不知道的实际情况.
Chr*_*irk 26
在回答来自肯特·贝克,JUnit的共同创造者(其中可能这个惯例起源,因为他早先苏尼特不会出现已包括assertEquals):
将一堆 assertEquals 排成一行。先有预期会让他们读得更好。
在我的回答的初始版本中,我说我不明白这一点。这是我在测试中经常看到的:
assertEquals(12345, user.getId());
assertEquals("kent", user.getUsername());
assertEquals("Kent Beck", user.getName());
Run Code Online (Sandbox Code Playgroud)
我认为首先使用实际值会更好地阅读。这将更多重复的样板放在一起,对齐我们正在测试其值的方法调用:
assertEquals(user.getId(), 12345);
assertEquals(user.getUsername(), "kent");
assertEquals(user.getName(), "Kent Beck");
Run Code Online (Sandbox Code Playgroud)
(我更喜欢这个顺序还有其他原因,但就这个为什么是另一种方式的问题而言,肯特的推理似乎是答案。)
然而,鲍勃·斯坦( Bob Stein)在下面发表了一条评论(很像这个评论),它暗示了一些“预期第一”已经实现的事情。主要思想是期望值通常可能更短——通常是文字或变量/字段,而不是可能的复杂方法调用。其结果:
assertEquals(12345, user.getId());
assertEquals("kent", user.getUsername());
assertEquals("Kent Beck", user.getName());
Run Code Online (Sandbox Code Playgroud)
谢谢,鲍勃!
的另一个目的assertEqual()是为人类读者演示代码。
一个简单的函数调用显示左侧的返回值和右侧的调用。
y = f(x)
Run Code Online (Sandbox Code Playgroud)
按照该约定,该功能的自测试演示可能如下所示:
assertEqual(y, f(x))
Run Code Online (Sandbox Code Playgroud)
订单是(预期的,实际的)。
这是 sum() 函数的演示,左侧是文字预期返回值,右侧是计算实际返回值的函数调用:
assertEqual(15, sum((1,2,3,4,5)))
Run Code Online (Sandbox Code Playgroud)
同样,这里有一个表达式的演示。按(预期的,实际的)顺序也是很自然的:
assertEqual(4, 2 + 2)
Run Code Online (Sandbox Code Playgroud)
另一个原因是风格。如果你喜欢排列,左边的预期参数更好,因为它往往更短:
assertEqual(42, 2 * 3 * 7)
assertEqual(42, (1 << 1) + (1 << 3) + (1 << 5))
assertEqual(42, int('110', int('110', 2)))
Run Code Online (Sandbox Code Playgroud)
我怀疑这解决了@ChrisPovirk 提出的关于 Kent Beck 所说的“预期首先让他们读得更好”的谜团。
感谢Andrew Weimholt和Ganesh Parameswaran提供这些公式。
这是一个非常有趣的话题,这里也有很多非常有教育意义的答案!这是我从他们那里学到的:
Intuitive/counter-intuitive 可以被认为是主观的,所以不管它最初定义的顺序是什么,也许我们 50% 的人都不会高兴。
就我个人而言,我更喜欢将其设计为assertEqual(actual, expected),因为鉴于assert和之间的概念相似性if,我希望它遵循的规范if actual == expect,例如,if a == 1。
(PS:确实有不同的意见,提示写if语句“逆序”,即if(1==a) {...}为了防止你不小心漏了一个=。但这种风格远非常态,即使在C/ C++ 世界。如果您碰巧正在编写 Python 代码,那么首先您就不会受到那个讨厌的错别字的影响,因为if a = 1在 Python 中无效。)
这样做的实际令人信服的理由assertEqual(expect, actual)是,您语言中的 unittest 库可能已经按照该顺序生成可读的错误消息。例如,在Python中,当你这样做assertEqual(expected_dictionary, actual_dictionary),单元测试将显示实际丢失的钥匙前缀-和额外的键前缀+,只是当你做一个像git diff old_branch new_branch。
无论直观与否,这是坚持assertEqual(expected, actual)顺序的唯一最有说服力的理由。如果你碰巧不喜欢它,你最好还是接受它,因为“实用胜过纯洁”。
最后,如果您需要一种方法来帮助您记住顺序,则此答案assertEqual(expected_result, actual_calculation)可与赋值语句 order进行比较result = calculate(...)。这可能是记住事实上的行为的好方法,但恕我直言,这不是该顺序无可争议的推理更直观。
所以你来了。快乐assertEqual(expect, actual)!
我同意一致性是#1的共识,但如果你正在评估这个问题,比较字典的行为可能是一个有用的数据点.
当我在差异上看到"+"时,我将其读作"正在测试的程序添加了这个".同样,个人偏好适用.
注意:我使用按字母顺序排列的键并使字典更长,以便只有中间键会因示例的清晰度而改变.其他场景显示更多混淆的差异.另外值得注意的是,assertEqual在> = 2.7和> = 3.1中使用assertDictEqual
exl.py
from unittest import TestCase
class DictionaryTest(TestCase):
def test_assert_order(self):
self.assertEqual(
{
'a_first_key': 'value',
'key_number_2': 'value',
'z_last_key': 'value',
'first_not_second': 'value',
},
{
'a_first_key': 'value',
'key_number_2': 'value',
'z_last_key': 'value',
'second_not_first': 'value',
}
)
Run Code Online (Sandbox Code Playgroud)
输出:
$ python -m unittest exl
F
======================================================================
FAIL: test_assert_order (exl.DictionaryTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "exl.py", line 18, in test_assert_order
'second_not_first': 'value',
AssertionError: {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'first_ [truncated]... != {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'second [truncated]...
{'a_first_key': 'value',
- 'first_not_second': 'value',
'key_number_2': 'value',
+ 'second_not_first': 'value',
'z_last_key': 'value'}
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Run Code Online (Sandbox Code Playgroud)
xUnit测试约定是预期/实际的。所以,对于许多人来说,这是自然的顺序,因为这就是他们学到的。
有趣的是,与 xUnit 框架的惯例不同,qunit 代表实际/预期。至少使用 JavaScript,您可以创建一个封装旧函数的新函数并将其分配给原始变量:
var qunitEquals = equals;
equals = function(expected, actual, message) {
qunitEquals(actual, expected, message);
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20192 次 |
| 最近记录: |