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

时间:2010-03-08 21:42:13

标签: debugging assert

为什么这么多assertEquals()或类似函数将预期值作为第一个参数而实际值作为第二个参数?
这对我来说似乎是违反直觉的,所以这种不寻常的订单有什么特别的原因吗?

8 个答案:

答案 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)

测试 firstsecond 是否相等。如果比较的值不相等,则测试将失败。

但是,如果您查看文档中的大多数示例,它们会首先放置接收到的值,然后放置期望值(与您的问题帖子声称的相反):

<块引用>
self.assertEqual(self.widget.size(), (50,50), 'incorrect default size')

所以我会说约定是assertEqual(got, expected),而不是相反!

无论如何,您的测试仍然有效。

答案 5 :(得分:1)

来自answerKent 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)

这是一个很有启发性的话题,这里也有很多很有教育意义的答案!这是我从他们那里学到的东西:

  1. 直觉/反直觉可以被认为是主观的,因此无论最初定义的顺序是什么,50% of us would not be happy

  2. 我个人更希望将其设计为assertEqual(actual, expected),因为鉴于assertif之间的概念相似性,我希望它遵循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中无效。)

  3. 进行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"

  4. 最后,如果您需要一种方法来记住顺序,this answer会将assertEqual(expected_result, actual_calculation)与赋值语句顺序result = calculate(...)进行比较。记忆事实行为可能是一个很好的方法,但是恕我直言,这并不是说该命令的直觉理由更直观。

所以,您去。 assertEqual(expect, actual)高兴!

答案 7 :(得分:-2)

我听到的解释是它来自TDD。

在“测试驱动开发”中,从测试开始,然后编写代码。

通过编写期望值开始断言,然后调用应该产生期望值的代码,这就是这种心态的迷你版本。

当然,这可能只是人们讲的一个故事。不知道这是有意识的原因。