在单元测试中使用多个断言是一种不好的做法吗? [已关闭]

问题描述 投票:0回答:8

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

unit-testing assert
8个回答
53
投票

有时,每个测试用例我只有一个

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
    }
}

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

  • 不要有多个
    assert
    ,这取决于先前执行的副作用。
  • assert
    组合在一起,测试相同的功能/特性或其方面 - 不需要时无需多个单元测试用例的开销。
  • 任何上述规则都应被实用性和常识所推翻。您可能不希望有一千个单元测试用例,每个单元测试用例(甚至多个断言)中只有一个断言,并且您也不希望单个测试用例具有数百个
    assert
    语句。

19
投票

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

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


12
投票

您的单元测试应该相当细粒度。通常,断言越少,您的测试就越有可能针对特定功能,而不是在同一测试中混合测试多个功能。这是否意味着所有测试都应该只有一个断言?不,但如果我发现多个断言,可能会在同一单元测试中测试多个内容,我会认为它是“测试气味”。像对待代码气味一样对待这种“气味”,并重构测试以改进它,以便它只测试一个“事物”——即使它需要多个断言。

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

var result = controller.Action() as ViewResult;

Assert.IsNotNull( result );
Assert.AreEqual( viewName, result.ViewName );

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


6
投票

对我来说,在单元测试中有多个断言是很常见的。我通常有一个前提条件的断言,然后是预期后置条件的断言。

考虑:

assert(list.isEmpty());

FetchValues(list);

assert(list.count == expectedItemCount);

AssertValuesMatch(list,expectedValues);

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


2
投票

我不认为这是不好的做法。单元测试可以做任何他们想做的事情:断言、记录到文件、向管理层发送侮辱性短信等等。

“可能”的问题是,增加的复杂性可能会改变被测程序的行为,但如果您小心的话,这种情况很少发生,并且无论如何都可以发现。


2
投票

您可能还会对这篇文章感兴趣:

https://timetocode.wordpress.com/2016/06/01/zen-of-unit-testing/


0
投票

我尝试断言每一步,直到并包括我的测试的具体目标。


-3
投票

这是“想太多”的例子。

© www.soinside.com 2019 - 2024. All rights reserved.