【发布时间】:2010-10-20 05:40:19
【问题描述】:
在一个单元测试中拥有多个断言是不好的做法吗?有关系吗?
【问题讨论】:
-
我不认为这是一个骗局,@mek。您的链接用于测试中的多个检查,这似乎用于断言以外的其他内容。
标签: unit-testing assert
在一个单元测试中拥有多个断言是不好的做法吗?有关系吗?
【问题讨论】:
标签: unit-testing assert
不,这不是一个坏习惯。如果您正在测试的方法返回一个类,您应该测试应该设置的不同变量。为此,您不妨使用一个单元测试。
但是,如果您在一个单元测试中测试多个功能,那么当它失败时,您就不清楚是哪些功能导致了问题。记住单元测试是你的朋友,所以让他们帮助你。让您可以轻松查看问题所在,以便您进行修复。
【讨论】:
我不认为这是不好的做法。单元测试可以做任何他们想做的事情:断言、记录到文件、向管理层发送侮辱性 SMS 消息等等。
可能的问题是,增加的复杂性可能会改变被测程序的行为,但如果你小心的话,这种情况很少发生,而且无论如何都会被发现。
【讨论】:
有时我每个测试用例只有一个assert,但我想更多时候我有几个assert 语句。
我见过@Arkain 逃避的情况,其中一段非常大的代码只有一个单元测试套件,只有几个测试用例,它们都标记为testCase1、testCase2 等,每个测试用例都有数百个断言。更好的是,每个条件通常取决于先前执行的副作用。每当构建失败时,总是在这样的单元测试中,需要相当长的时间来确定问题出在哪里。
但另一个极端是您的问题所暗示的:每个可能的条件都有一个单独的测试用例。根据您要测试的内容,这可能是有道理的,但每个测试用例通常有几个 asserts。
例如,如果您写了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 不能超过一个。asserts 组合在一起测试相同的功能/特性或其方面——在不需要时不需要多个单元测试用例的开销。assert 语句。【讨论】:
没关系。唯一重要的是您的单元测试将涵盖所有可能的错误。
这是一个“过度思考”的例子。
【讨论】:
您的单元测试应该是相当细粒度的。通常,断言越少,您的测试就越有可能针对特定功能而不是在同一测试中混合测试多个功能。这是否意味着所有测试都应该只有一个断言?不,但如果我发现几个断言,我会认为这是一种“测试气味”,可能会在同一个单元测试中测试多个东西。像对待代码异味一样对待这种“气味”,并重构测试以改进它,以便它只测试一个“事物”——即使它需要多个断言。
例如,我现在正在做一个 MVC 项目,我编写的测试之一是正确的视图是由动作呈现的。如果不同的代码路径可能导致不同的视图,则实际上可能有几个。这就是我将其定义为正确视图的方式:结果是正确的类型并且具有正确的名称。这需要两个断言,但我只测试一件事。
var result = controller.Action() as ViewResult;
Assert.IsNotNull( result );
Assert.AreEqual( viewName, result.ViewName );
我可能会对模型做类似的事情,但我不会在与检查视图相同的测试中测试模型是否正确,因为这些是代码行为的不同方面。我可以更改预期的模型或视图,并将其放在单独的测试中,只有那些与该方法的特性相关的测试需要更改。
【讨论】:
放入所有你想要的断言。认真的。
我尝试断言直到并包括我的测试的具体目标的每一步。
【讨论】:
对我来说,在单元测试中有多个断言是很常见的。我通常有一个前置条件的断言,然后是预期的后置条件的断言。
考虑:
assert(list.isEmpty());
FetchValues(list);
assert(list.count == expectedItemCount);
AssertValuesMatch(list,expectedValues);
是的,我可以将两个后置条件分成两个测试,但根据 FetchValues 的成本,可能会不必要地减慢整个测试过程。
【讨论】:
我绝对应该在测试方法中只使用一个断言!使用许多断言可能是您正在测试不止一件事的代码味道。此外,有人可能会在您的测试中添加新的断言而不是编写另一个断言。当第一个断言失败时,您如何理解其他断言如何完成?
您可能还会发现这篇文章很有趣:https://timetocode.wordpress.com/2016/06/01/zen-of-unit-testing/
【讨论】: