您认为对结果执行多个断言的最简洁方法是什么?在过去,我已经对它们进行了相同的测试但是这开始感觉有点脏,我刚刚使用设置玩了另一个想法。
[TestFixture]
public class GridControllerTests
{
protected readonly string RequestedViewId = "A1";
protected GridViewModel Result { get; set;}
[TestFixtureSetUp]
public void Get_UsingStaticSettings_Assign()
{
var dataRepository = new XmlRepository("test.xml");
var settingsRepository = new StaticViewSettingsRepository();
var controller = new GridController(dataRepository, settingsRepository);
this.Result = controller.Get(RequestedViewId);
}
[Test]
public void Get_UsingStaticSettings_NotNull()
{
Assert.That(this.Result,Is.Not.Null);
}
[Test]
public void Get_UsingStaticSettings_HasData()
{
Assert.That(this.Result.Data,Is.Not.Null);
Assert.That(this.Result.Data.Count,Is.GreaterThan(0));
}
[Test]
public void Get_UsingStaticSettings_IdMatches()
{
Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId));
}
[Test]
public void Get_UsingStaticSettings_FirstTimePageIsOne()
{
Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1));
}
}
答案 0 :(得分:15)
在同一个测试中有多个断言可以导致Assertion Roulette,所以你应该小心谨慎。
然而,当断言无关时,断言轮盘主要是一个问题。如果它们在概念上密切相关,那么许多断言通常可以被视为单个逻辑断言。
在许多情况下,通过在自定义类型或方法中显式封装此类逻辑断言,您可以充分利用这两个世界。
答案 1 :(得分:3)
您需要遵守的是Arrange, Act, Assert的模式(然后结束测试)。在您的情况下,所有安排都在TestFixtureSetUp
中,正在测试的操作也是如此。我会稍微重新安排一下,当你有更多的测试时,它可能会变得笨重。正如Dockers所指出的那样,应该避免繁重的测试设置,它们会成为问题 - 它们在课堂上的所有测试中都“一刀切”,因此可能比大多数测试需要的更重。
如果您想继续进行另一个后续行动,然后再进行更多断言,请将其置于单独的测试中。
在同一个测试中放置多个断言没有问题,只要它们有助于测试相同的东西(即同一个“逻辑断言”的一部分)。在这种情况下,this.Result.Data的内容上的任何数量的断言都可以由我完成 - 它们都将检查相同的结果值。您的Get_UsingStaticSettings_HasData
非常清楚地表达了这一点。最好在每个断言上使用唯一的失败消息,以便更容易判断哪个断言失败。
或者,您可以在单个方法中包装相关的断言。如果您不止一次使用它,这对于通常的DRY原因很有用,但除此之外我不认为这是一个很大的区别。
摘要中
*每次测试都要执行一次操作
*在行动之后,使用尽可能多的相关断言来测试一件事
*在那里结束测试。
答案 2 :(得分:2)
您可以使用Oapt - NUnit Addin为每次测试运行一次断言:
[TestFixture]
public class GridControllerTests
{
[TestCase, ForEachAssert]
public void Get_UsingStaticSettings_Assign()
{
var dataRepository = new XmlRepository("test.xml");
var settingsRepository = new StaticViewSettingsRepository();
var controller = new GridController(dataRepository, settingsRepository);
var result = controller.Get("A1");
AssertOne.From(
() => Assert.That(this.Result,Is.Not.Null),
() => Assert.That(this.Result.Data,Is.Not.Null),
() => Assert.That(this.Result.Data.Count,Is.GreaterThan(0)),
() => Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId)),
() => Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1)));
}
}
这将创建5个不同的测试用例,每个断言一个。
答案 3 :(得分:0)
我倾向于只在他们自己有价值的情况下自己断言。如果我想自己断言,我会做一个自定义断言:
AssertThatMyObjectMatches(field1, field2, field3, field4, myObject);
但有时候,我喜欢在测试中有多个例子。如果有一半的行为没有另一半没有价值,我会这样做。
Assert.True(list.IsEmpty());
list.Add(new Thing());
Assert.False(list.IsEmpty());
其他人,包括Ruby社区的大部分人,都对此有不同的看法。它主要由Dave Astels的博客文章驱动,在这里:
http://www.artima.com/weblogs/viewpost.jsp?thread=35578
我发现“每个测试的一个断言”方法对于诸如验证之类的东西非常有用,其中每个小方面都是有价值的。否则我不会那么担心。
无论对你和你的团队有什么用,都是正确的方法。当我更好地了解正确的事情时,我倾向于做任何看起来简单易行的事情,以后做出正确的事情。我还在更复杂的示例中添加了大量单元级Given / When / Then
注释,如果它变得太复杂而无法理解,则会拆分该类。
以这种方式编写测试的原因并非如此,以至于您可以捕获破坏的东西。这是为了帮助人们理解代码并在不破坏事物的情况下对其进行更改。