在unit testing中有多个断言是不好的做法?
在unit testing中有多个断言是不好的做法? 有关系吗?
有时我每个testing用例都只有一个assert
,但是我认为我经常有几个assert
。
我见过@Arkain所说的情况,一个非常大的代码只有一个单一的testing套件,只有几个testing用例,它们都被标记为testCase1
, testCase2
等,每个testing用例都有数百个断言。 更好的是,每个条件通常取决于之前执行的副作用。 每当构build失败,总是在这样的unit testing中,花费相当长的时间来确定问题出在哪里。
但另一个极端就是你的问题所暗示的:针对每种可能的情况的一个单独的testing用例。 根据你正在testing的内容,这可能是有道理的,但是我经常assert
每个testing用例有几个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 } }
一些简单的规则,我可以想到多less断言的testing用例:
- 不要有一个以上的
assert
取决于以前的执行的副作用。 - 组一起声明testing相同的function/特征或方面 – 当没有必要时,不需要多个unit testing用例的开销。
- 任何上述规则都应该被实用性和常识所覆盖。 你可能不需要在每个(甚至几个断言)中使用单个断言的千个unit testing用例,而且你也不希望有一个包含数百个
assert
语句的testing用例。
不,这不是一个坏习惯。 如果您正在testing的方法返回一个类,则应该testing应该设置的不同variables。 为此目的,你可以使用一个unit testing。
但是,如果您正在一个unit testing中testing多个function,那么在哪个function出现问题时就不会很清楚。 记住unit testing是你的朋友,所以让他们帮助你。 让它很容易看到出了什么问题,所以你可以去修复它。
你的unit testing应该是相当细致的。 通常,断言越less,您的testing就越有可能针对特定function,而不是在同一testing中混合testing多个function。 这是否意味着所有的testing应该只有一个断言? 不,但如果我发现了几个断言,我会认为这是一个“testing气味”,可能在同一个unit testing中testing多个东西。 对待这个“味道”就像代码味道一样,并重构testing以改进它,以便它只testing一个“事物” – 即使它需要多个断言。
例如,我正在做一个MVC项目,我写的一个testing是正确的视图是由行动呈现。 如果不同的代码path可能导致不同的视图,实际上可能有几个这样的情况。 这是我如何定义它是正确的看法:结果是正确的types和正确的名称。 这需要两个断言,但我只testing一件事情。
var result = controller.Action() as ViewResult; Assert.IsNotNull( result ); Assert.AreEqual( viewName, result.ViewName );
我可能会对模型做类似的事情,但是我不会在与检查视图相同的testing中testing模型是否正确,因为这些是代码行为的不同方面。 我可以改变预期的模型或视图,并通过将其放入单独的testing中,只需要改变与该方法的该特征有关的那些testing。
对我来说,在unit testing中有多个断言是很常见的。 我通常有一个先决条件的断言,然后断言预期的后置条件。
考虑:
assert(list.isEmpty()); FetchValues(list); assert(list.count == expectedItemCount); AssertValuesMatch(list,expectedValues);
是的,我可以将两个后期条件分解成两个testing,但取决于FetchValues的成本可能会不必要地减慢整个testing过程。
我不认为这是不好的做法。 unit testing可以做任何他们想要的:断言,login到文件,发送侮辱的SMS消息到pipe理,任何事情。
可能的问题是增加的复杂性可能会改变被testing程序的行为,但是如果你小心并且可以被发现的话,情况就不会那么严重了。
把所有的断言放在你想要的。 认真。
我试图断言,直到包括我的testing的具体目标的每一步。
我绝对只能在testing方法中使用一个断言! 使用许多断言可能是你正在testing多个东西的代码气味。 而且,有人可能会添加新的断言到你的testing中,而不是写另一个断言。 你怎么能理解你的其他断言在第一个失败时是如何完成的呢?
您也可能会发现这篇文章有趣: https : //timetocode.wordpress.com/2016/06/01/zen-of-unit-testing/
没关系。 唯一重要的是你的unit testing将覆盖所有可能的错误。
这是“过度思考”的一个例子。
“unit testing”应该testing1个单元,所以要尽可能小,只testing1个确定的东西。 我会build议只有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"); }