在这个单元测试中检查这么多东西有什么问题吗?:
ActualModel = ActualResult.AssertViewRendered() // check 1
.ForView("Index") // check 2
.WithViewData<List<Page>>(); // check 3
CollectionAssert.AreEqual(Expected, ActualModel); // check 4
此测试的主要目标是验证返回正确的视图(检查2)并且它包含正确的数据(检查4)。
通过将其分成多个测试,我可以获得任何收益吗?我一切都是为了做正确的事情,但如果它没有实际价值,我就不会分手了。
我对单元测试很陌生,所以请保持温和。
答案 0 :(得分:29)
正如其他人所指出的,最好在每个测试中坚持使用一个断言以避免丢失信息 - 如果第一个断言失败,你不知道后面的断言是否也会失败。你必须用较少的信息解决问题 - 这可能(可能会)更难。
一个非常好的参考是Roy Osherove的Art of Unit Testing - 如果你想要开始使用单元测试,你可能会比从这里开始做得更糟。
答案 1 :(得分:12)
未来读者注意到这个问题及其重复的Is it bad practice to have more than one assertion in a unit test?具有相反的多数意见,所以请仔细阅读并自行决定。
我的经验是,最有用的测试量不是断言,而是场景 - 也就是说,对于给定的一组初始条件和方法调用,应该有一个单元测试,并且必须有多个断言断言预期的最终条件。每个断言进行一次单元测试会导致重复设置或曲折的变通方法以避免重复(例如我最近看到的可怕的深度嵌套的rspec上下文)。它还会增加测试次数,大大减慢你的套件。
答案 2 :(得分:8)
只要每个断言都有一个唯一且识别失败的消息,你应该是好的并且会回避任何断言轮盘问题,因为不难判断哪个测试失败了。使用常识。
答案 3 :(得分:7)
我在这个问题上找到了一个不同的论点(至少对我自己而言):
如果他们正在测试相同的东西,可以使用多个断言。
例如,可以这样做:
Assert.IsNotNull(value);
Assert.AreEqual(0, value.Count);
为什么呢? - 因为这两个断言并没有隐藏测试的意图。 如果第一个断言失败,则意味着第二个断言也会失败。实际上,如果我们删除第一个断言,那么第二个断言无论如何都会失败(带有空引用异常 - !!!){{ 1}}为空。如果情况并非如此,那么我们不应该将这两个断言放在一起。
所以,这是错误的:
value
正如我上面提到的,如果第一个断言失败,则没有关于第二个断言的明确指示 - 我们仍然想知道第二个断言会发生什么(即使第一个断言失败)。因此,这两个断言属于两个不同的单元测试。
结论:在正确完成之后放置一个或多个断言成为首选问题 - 我们是否希望在测试结果中看到断言异常,或者我们是否希望看到其他一些异常以及特殊情况。
答案 4 :(得分:2)
最好在每个测试中只使用一个断言以避免Assertion Roulette。
如果您需要设置相同的方案来根据相同的前提测试多个条件,最好将设置代码提取到共享帮助器方法,然后编写几个调用此辅助方法的测试。
这确保每个测试用例只测试一件事。
与往常一样,此规则有例外,但因为您是新的进行单元测试,我建议您坚持使用每个单元测试的一个断言规则直到你知道什么时候可以偏离。
答案 5 :(得分:0)
我知道这是一个老问题,但我想我会补充一下。
通常我会在每个测试用例中尽可能少地断言。通常可以编写测试以节省大量不同的断言。
假设我对一个方法的单元测试,该方法从名称的组成部分创建称呼(例如史密斯先生)。我想用大量不同的场景来检查它,没有必要对每个场景进行单独的测试。
鉴于以下代码,有许多不同的断言。当它们失败时,你可以一次修复它们,直到断言停止。
Assert.AreEqual("Mr Smith", GetSalutation("Mr", "J", "Smith"));
Assert.AreEqual("Mr Smith", GetSalutation("Mr", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "J", "Smith"));
另一种方法是保留问题的数量并在结束时断言。
int errorCount = 0;
string result;
result = GetSalutation("Mr", "J", "Smith");
if (result == "Mr Smith")
errorCount++;
result = GetSalutation("Mr", "John", "Smith");
if (result == "Mr Smith")
errorCount++;
Assert.AreEqual(0, errorCount);
在现实世界中,我可能会添加一些Trace命令来编写输出窗口失败的各个测试的详细信息