在这种情况下,坚持每个测试一个断言是否愚蠢的一致性?


10

我有一个正在测试的课程。该类具有一个功能:apply(List<IRule> rules, List<ITarget> targets);

在一个测试中,我想确保每个目标都已通过一个规则,例如:

rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));

在我看来,将自己限制在一条断言中就等于是妖精。在这个假设中我是否正确,还是可以通过其他方式断言每个目标实际上都已经过测试?


我可以看到伙伴们!
罗斯·帕特森

Answers:


15

这三个断言实质上是一种检验。您正在测试集合上方法的行为,以确保每个项目都是特定调用的参数(即,每个项目均已正确处理)。

与使用多个断言的替代方法相比,使用三种不同的方法对数据进行三次设置非常浪费且可读性较低。

单一的断言“规则”更多地是关于使用相同的方法(本质上测试不同的事物)做出不同类型的断言,这在这种情况下(您正在测试单个行为)实际上并不适用。


3
确实:规则是每个单元测试一个逻辑上的断言。您可以将它们归为一个较高的级别,以便可以在不同的测试中重复使用。
Laurent Bourgault-Roy 2012年

5

我相信,每个测试规则都必须有一个断言,以使您的测试专注于一个问题。如果您在一项测试中测试了20项内容,那么很难说出覆盖范围是什么。您知道当您在没有单词单词的情况下无法命名测试方法时,就会引起问题。例如,如果将您的测试方法更准确地命名为testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur(),则您可能在一项测试中测试了太多。

对于您的情况,我认为可以断言三遍。如果要使代码更具可读性,可以将这三个断言提取到名为的方法中assertWasCalledOnTargets(...)


3

对于您的特定示例,如果执行以下操作,则可以使用“一个”断言语句:

foreach target in targets
{
     rule1.AssertWasCalled(fnord => fnord.Test(target))
}

我这样做是为了避免对一个测试中有多个断言感到内。


我以前做过 不错的选择。它很容易阅读,您可以了解其操作的性质。
CokoBWare 2012年

1

我也为此感到挣扎。

纯粹主义者(对我而言)每次测试都坚持一个主张,所以我会* 确切地 *知道事情发生的地方。

然后我发现自己剪切/粘贴了大量相同的,冗余的测试设置代码。在第三或第四层之后,您开始说:“好!够了!”

我的折衷办法是找到“永不中断”的方面。然后将这些片段层叠在一起,然后添加一个可能会破坏的新元素。需要明确的是,在一个测试中对多个易失性区域进行分层将违反此折衷方案。


1
您应该退房Assume。我今天才了解。
韦恩·沃纳

1

如果的设置代码target1与的设置代码不同target2,则这种切角会导致最终导致过长的测试初始化​​代码。反过来,这要么是一团糟,要么最终会被重构和重新使用。如果您的测试足够复杂以至于需要进行重构,那么您的测试可能会测试不止一件事。

如果每个目标的设置代码基本相同,则将您的测试分为多个单独的测试可能是过分的。

如果target1target2是同一接口的不同实现,则应该在该接口上添加单元测试(并允许您的测试框架为该接口的每种实现生成测试)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.