单元测试:为什么预期的参数总是在相等测试中首先出现?

时间:2012-02-17 15:45:42

标签: unit-testing

为什么每个单元测试框架(我都知道:)要求相等测试中的期望值始终是第一个参数:

Assert.AreEqual(42, Util.GetAnswerToLifeTheUniverseAndEverything());

assertEquals(42, Util.GetAnswerToLifeTheUniverseAndEverything());

我现在已经习惯了,但是我尝试教单元测试的每个编码器都会错误地反驳我完全理解的论点。谷歌没有帮助,也许这里的核心单位测试人员之一知道答案?

9 个答案:

答案 0 :(得分:36)

似乎大多数早期的框架在实际之前使用期望的(虽然有些未知的原因,骰子可能会滚动?)。然而,随着编程语言的发展和代码的流畅性的增加,这个顺序发生了逆转。大多数流畅的界面通常会尝试模仿自然语言,单元测试框架也不例外。

在断言中,我们要确保某些对象符合某些条件。这是自然语言形式,就好像你要解释你可能会说的测试代码一样

  

“在此测试中,我确保计算值等于5”

而不是

  

“在此测试中,我确保5等于计算值”。

差异可能不是很大,但让我们进一步推动它。考虑一下:

Assert.That(Roses, Are(Red));

听起来很对。现在:

Assert.That(Red, Are(Roses));

嗯..?如果有人告诉你玫瑰是红色的,你可能不会太惊讶。换句话说,红色是玫瑰,引发了可疑的问题。 Yoda,有人吗?

That doesn't sound natural at all

尤达正在提出一个重要观点 - 颠倒顺序会迫使你think

当你的断言更复杂时,它会变得更加不自然

Assert.That(Forest, Has.MoreThan(15, Trees));

你会如何逆转那一个? 森林里有超过15棵树

这种说法(流利性作为修改的驱动因素)在某种程度上反映在NUnit所经历的变化中 - 最初(Assert.AreEqual)它在实际<之前使用期望 / em>(旧式)。流畅的扩展(或使用NUnit的术语,基于约束的 - Assert.That)颠倒了这个顺序。

答案 1 :(得分:13)

我认为现在只是一个惯例,正如你所说的那样,每个单元测试框架(我知道)&#34;都采用了它。如果您正在使用框架,那么切换到使用相反约定的另一个框架会很烦人。所以(例如,如果您正在编写新的单元测试框架),您最好遵循现有的约定。 我相信这来自一些开发人员喜欢编写相等测试的方式:

if (4 == myVar)

为了避免任何不需要的任务,错误地写了一个&#34; =&#34;而不是&#34; ==&#34;。在这种情况下,编译器将捕获此错误,您将避免尝试修复奇怪的运行时错误的许多麻烦。

答案 2 :(得分:5)

没有人知道,这是永无止境的混乱的根源。然而,并非所有框架都遵循这种模式(更令人困惑):

  1. FEST-Assert使用普通顺序:

    assertThat(Util.GetAnswerToLifeTheUniverseAndEverything()).isEqualTo(42);
    
  2. Hamcrest

    assertThat(Util.GetAnswerToLifeTheUniverseAndEverything(), equalTo(42))
    
  3. ScalaTest并没有真正区分:

    Util.GetAnswerToLifeTheUniverseAndEverything() should equal (42)
    

答案 3 :(得分:5)

我不知道,但我参与了几个关于平等测试论证顺序的动画讨论。

有很多人在想

if (42 == answer) {
  doSomething();
}

优于

if (answer == 42) {
  doSomething();
}

基于C语言。原因是如果你不小心把一个等号:

if (42 = answer) {
  doSomething();
}

会给你一个编译器错误,但是

if (answer = 42) {
  doSomething();
}

可能不会,并且肯定会引入一个可能难以追踪的错误。所以谁知道,也许设置单元测试框架的人/人习惯于以这种方式思考相等测试 - 或者他们正在复制已经以这种方式设置的其他单元测试框架。

答案 4 :(得分:1)

我认为这是因为JUnit是大多数单元测试框架的前身(并不是它是第一个单元测试框架,但它开始了单元测试的爆炸性增长)。由于JUnit采用了这种方式,所有后续框架都复制了这个表单,并成为一种约定。

为什么JUnit这样做?我不知道,请问Kent Beck!

答案 5 :(得分:0)

他们必须选择一个会议。如果你想反转它,试试Hamcrest匹配器。它们旨在帮助提高可读性。这是一个基本样本:

import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.core.Is.is;

public HamcrestTest{
   @Test
   public void matcherShouldWork(){
       assertThat(   Math.pow( 2, 3 ),  is( 8 )  );
   }
}

答案 6 :(得分:0)

因为大多数程序员都没有阅读Self-Reliance by Ralph Waldo Emerson

答案 7 :(得分:0)

我对此的看法是避免任何例外,例如:42.equals(null)与null.equals(42)

预计为42 null是实际的

答案 8 :(得分:-1)

将预期值放在首位是合乎逻辑的,因为它是第一个已知值。

在手动测试的环境中考虑一下。手动测试将写入预期值,之后记录实际值。