在单元测试中有多个断言是不好的做法吗?

leo*_*ora 43 unit-testing assert

在单元测试中有多个断言是不好的做法吗?有关系吗?

Jar*_*aus 42

有时我assert每个测试用例只有一个,但我想我经常会有几个assert语句.

我见过@Arkain逃避到,其中一个非常大的代码有一个单一的单元测试套件,只需几个测试案例的情况下,它们都标记testCase1,testCase2等等,并且每个测试用例有数百个断言的.更好的是,每种情况通常都取决于先前执行的副作用.每当构建失败时,总是在这样的单元测试中,确定问题所在的位置需要相当长的时间.

但另一个极端是你的问题所暗示的:针对每种可能情况的单独测试案例.根据您正在测试的内容,这可能有意义,但通常assert每个测试用例都有几个.

例如,如果您写了java.lang.Integer,您可能会遇到以下情况:

public void testValueOf() {
    assertEquals(1, Integer.valueOf("1").intValue());
    assertEquals(0, Integer.valueOf("0").intValue());
    assertEquals(-1, Integer.valueOf("-1").intValue());
    assertEquals(Integer.MAX_VALUE, Integer.valueOf("2147483647").intValue());
    assertEquals(Integer.MIN_VALUE, Integer.valueOf("-2147483648").intValue());
    ....
}

public void testValueOfRange() {
    assertNumberFormatException("2147483648");
    assertNumberFormatException("-2147483649");
    ...
}

public void testValueOfNotNumbers() {
    assertNumberFormatException("");
    assertNumberFormatException("notanumber");
    ...
}
private void assertNumberFormatException(String numstr) {
    try {
        int number = Integer.valueOf(numstr).intValue();
        fail("Expected NumberFormatException for string \"" + numstr +
             "\" but instead got the number " + number);
    } catch(NumberFormatException e) {
        // expected exception
    }
}
Run Code Online (Sandbox Code Playgroud)

一些简单的规则,我可以想到有多少断言放在一个测试用例中:

  • 不要有多个assert依赖于先前执行的副作用.
  • 组合assert在一起测试相同的功能/特征或其方面 - 在没有必要时不需要多个单元测试用例的开销.
  • 任何上述规则都应该被实用性和常识所覆盖.您可能不希望在每个(甚至几个断言)中使用单个断言的千个单元测试用例,并且您不希望单个测试用例包含数百个assert语句.

  • +1表示"不要有多个断言取决于先前执行的副作用." (9认同)

Jes*_*sen 17

不,这不是一个坏习惯.如果您要测试的方法返回一个类,则应测试应该设置的不同变量.为此,您不妨使用一个单元测试.

但是,如果您在一个单元测试中测试多个功能,那么当它失败时哪个功能导致问题就不会很清楚.记住单元测试是你的朋友,所以让他们帮助你.让它很容易看到出了什么问题,以便你可以修复它.


tva*_*son 10

您的单元测试应该是合理的细粒度.通常,断言越少,您的测试越有可能针对特定功能而不是在同一测试中混合测试多个功能.这是否意味着所有测试只应该有一个断言?不,但如果我发现了几个断言,我会认为它是一种"测试气味",可能在同一单元测试中测试多个东西.像对待代码一样嗅到这种"气味"并重构测试以对其进行优化,使其仅测试一个"事物" - 即使它需要多个断言.

例如,我现在正在做一个MVC项目,我写的一个测试是操作呈现正确的视图.如果不同的代码路径可能导致不同的视图,则实际上可能存在其中的几个.这就是我将其定义为正确视图的方式:结果是正确的类型并且具有正确的名称.这需要两个断言,但我只测试一件事.

var result = controller.Action() as ViewResult;

Assert.IsNotNull( result );
Assert.AreEqual( viewName, result.ViewName );
Run Code Online (Sandbox Code Playgroud)

我可能会对模型做类似的事情,但我不会在与检查视图相同的测试中测试模型是否正确,因为这些是代码行为的不同方面.我可以更改预期的模型或视图,并将其放在单独的测试中,只需要更改与该方法的该功能相关的那些测试.

  • 你可以删除第一个断言,因为如果第二个断言抛出nullreferenceexception,你知道它是null. (3认同)

Mik*_*keJ 6

对我而言,在单元测试中有多个断言是很常见的.我通常有一个先决条件的断言,然后断言预期的后置条件.

考虑:

assert(list.isEmpty());

FetchValues(list);

assert(list.count == expectedItemCount);

AssertValuesMatch(list,expectedValues);
Run Code Online (Sandbox Code Playgroud)

是的,我可以将两个后置条件分成两个测试,但是根据FetchValues的成本可能会不必要地减慢整个测试过程.

  • 由于断言不是彼此落后,这没关系.但这比"单元测试"更像是"自动化功能测试". (2认同)