为什么这么多assertEquals()
或类似函数将预期值作为第一个参数而实际值作为第二个参数?
这对我来说似乎是违反直觉的,所以这种不寻常的订单有什么特别的原因吗?
答案 0 :(得分:22)
因为作者有50%的机会匹配你的直觉。
由于其他超载
assertWhatever(explanation, expected, actual)
这个解释是你所知道的一部分,与预期的一致,就是你所知道的,而不是你在编写代码时不知道的实际情况。
答案 1 :(得分:5)
我同意一致性是#1的共识,但如果你正在评估这个问题,比较字典的行为可能是一个有用的数据点。
当我在差异上看到“+”时,我将其读作“正在测试的程序添加了这个”。同样,个人偏好也适用。
注意:我使用按字母顺序排列的键并使字典更长,以便只有中间键才会更改,以便清晰显示示例。其他场景显示更多混淆的差异。另外值得注意的是,assertEqual uses assertDictEqual in> = = 2.7和> = 3.1
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',
}
)
输出:
$ 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)
答案 2 :(得分:2)
xUnit测试约定是预期的/实际的。因此,对于许多人而言,这是他们所学到的自然顺序。
有趣的是,与xUnit框架的约定相比,qunit取决于实际/预期。至少使用javascript,你可以创建一个封装旧函数的新函数,并为其分配原始变量:
var qunitEquals = equals;
equals = function(expected, actual, message) {
qunitEquals(actual, expected, message);
};
答案 3 :(得分:2)
assertEqual()
的另一个目的是为人类读者演示代码。因为最简单的函数调用是result = function(parameters)
,所以人们习惯于想到左侧的返回值和右侧的调用。
因此,记录函数的测试将在左侧显示一个文字,在右侧显示一个调用。
assertEqual(15, sum((1,2,3,4,5)))
即(预期的,实际的)。与此类似。
assertEqual(4, 2 + 2)
答案 4 :(得分:2)
assertEqual
的文档将第一个参数命名为 first
,第二个参数命名为 second
:
assertEqual(first, second, msg=None)
测试 first
和 second
是否相等。如果比较的值不相等,则测试将失败。
但是,如果您查看文档中的大多数示例,它们会首先放置接收到的值,然后放置期望值(与您的问题帖子声称的相反):
<块引用>self.assertEqual(self.widget.size(), (50,50), 'incorrect default size')
所以我会说约定是assertEqual(got, expected)
,而不是相反!
无论如何,您的测试仍然有效。
答案 5 :(得分:1)
来自answer的Kent Beck是SUnit和JUnit的创建者(可能是该约定的发源地),
在一行中插入一串assertEquals。首先有了期望,会使他们的阅读更好。
但是,这与我自己的经历正好相反,我不得不怀疑自己是否误解了。这是我在测试中经常看到的内容:
assertEquals(user.getId(), 12345);
assertEquals(user.getUsername(), "kent");
assertEquals(user.getName(), "Kent Beck");
我认为首先使用 actual 值会更好。这将更多的重复样板放在一起,使我们正在测试其值的方法调用对齐:
<html>
<body>
<script>
function waitAndWrite(num) {
setTimeout(() => {
let text = "The number is " + num + "<br>";
document.write(text)
}, num * 1000)
}
for (let i = 0; i < 5; i++) {
waitAndWrite(i)
}
</script>
</body>
(还有其他一些原因,我更喜欢这种顺序,但是出于关于为什么的问题,相反,即使我没有肯特的推理也可以找到答案。了解。)
答案 6 :(得分:0)
这是一个很有启发性的话题,这里也有很多很有教育意义的答案!这是我从他们那里学到的东西:
直觉/反直觉可以被认为是主观的,因此无论最初定义的顺序是什么,50% of us would not be happy。
我个人更希望将其设计为assertEqual(actual, expected)
,因为鉴于assert
和if
之间的概念相似性,我希望它遵循the norm of if actual == expect
, for example, if a == 1
(PS:的确,prompts to write if statement in the "reverse order", i.e. if(1==a) {...}
有不同的意见,以防止您意外遗漏=
。但是,即使是在C / C ++世界。如果您碰巧正在编写Python代码,那么您一开始就不会受到那种讨厌的输入错误的影响,因为if a = 1
在Python中无效。)
进行assertEqual(expect, actual)
的实际令人信服的理由是,您所用语言中的unittest库可能已经按照该顺序生成了可读的错误消息。例如,在Python中,执行assertEqual(expected_dictionary, actual_dictionary)
,unittest will display missing keys in actual with prefix -
, and extra keys with prefix +
就像执行git diff old_branch new_branch
一样。
是否直观,这是坚持使用assertEqual(expected, actual)
顺序的唯一最令人信服的原因。如果您碰巧不喜欢它,则最好还是接受它,因为"practicality beats purity"。
最后,如果您需要一种方法来记住顺序,this answer会将assertEqual(expected_result, actual_calculation)
与赋值语句顺序result = calculate(...)
进行比较。记忆事实行为可能是一个很好的方法,但是恕我直言,这并不是说该命令的直觉理由更直观。
所以,您去。 assertEqual(expect, actual)
高兴!
答案 7 :(得分:-2)
我听到的解释是它来自TDD。
在“测试驱动开发”中,从测试开始,然后编写代码。
通过编写期望值开始断言,然后调用应该产生期望值的代码,这就是这种心态的迷你版本。
当然,这可能只是人们讲的一个故事。不知道这是有意识的原因。