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

时间:2009-04-17 23:03:41

标签: unit-testing assert

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

9 个答案:

答案 0 :(得分:40)

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

我已经看到@Arkain躲过的情况,其中一大段代码只有一个单元测试套件,只有几个测试用例,而且它们都标有testCase1,{{1}等等,每个测试用例都有数百个断言。更好的是,每种情况通常都取决于先前执行的副作用。每当构建失败时,总是在这样的单元测试中,确定问题的位置需要相当长的时间。

但另一个极端是你的问题所暗示的:针对每种可能情况的单独测试案例。根据您正在测试的内容,这可能有意义,但每个测试用例通常会有几个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语句。

答案 1 :(得分:16)

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

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

答案 2 :(得分:9)

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

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

var result = controller.Action() as ViewResult;

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

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

答案 3 :(得分:6)

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

考虑:

assert(list.isEmpty());

FetchValues(list);

assert(list.count == expectedItemCount);

AssertValuesMatch(list,expectedValues);

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

没关系。唯一重要的是你的单元测试将涵盖所有可能的错误。

这是“过度思考”的一个例子。

答案 6 :(得分:1)

输入您想要的所有断言。严重。

我试图断言我的测试的具体目标,包括我的测试的具体目标。

答案 7 :(得分:1)

我绝对应该在测试方法中只使用一个断言!使用许多断言可能是您正在测试不止一件事的代码气味。此外,有人可能会在测试中添加新断言,而不是编写另一个断言。当第一个断言失败时,你怎么能理解你的其他断言是如何完成的?

您可能还会发现这篇文章很有意思:https://timetocode.wordpress.com/2016/06/01/zen-of-unit-testing/

答案 8 :(得分:0)

“单元测试”应该测试1个单元,所以要尽可能小,只测试1个特定的东西。 我建议只有1个断言

但是我认为只要不是一个断言就可以有两个断言。

错误的例子

public void ValidateRulesEntry_Valid_ValidConditionsFromFile()
{
    string condition = "Target.HasValue";
    string returnMessage;

    bool successFul = CodeParserTryParseCondition(condition, out returnMessage);


    Assert.IsTrue(successFul);
    Assert.IsFalse(string.IsNullOrEmpty(returnMessage));
    Assert.IsTrue(returnMessage == "OK");

}