在 C# 中使用断言作用域执行多个断言
Fluent Assertions是一个 .NET 库,它提供了一系列有用的扩展方法,使我们能够以更自然的方式测试我们的 C# 代码。
例如,假设我们正在测试字符串的输出。如果没有 Fluent Assertions,我们可能会这样写:
string testString = "hello";
string expectedOutput = testString.ToUpper();
Assert.Equal(expectedOutput, "HELLO");
如果我们要使用 Fluent Assertions 编写这个测试,我们可以这样做:
string testString = "hello";
string expectedOutput = testString.ToUpper();
expectedOutput.Should().Be("HELLO");
看?更自然?
引入断言范围
让我们使用一个更广泛的例子。假设我有一个生成购物清单的类,如下所示:
public class ShoppingListGenerator
{
public static List<Item> GenerateItems()
{
return new List<Item>
{
new Item
{
Name = "Apple",
Quantity = 5
},
new Item
{
Name = "Banana",
Quantity = 1
},
new Item
{
Name = "Orange",
Quantity = 3
}
};
}
}
对于更复杂的单元测试,我们可能希望对多个属性进行断言,如下所示:
public class ShoppingListGeneratorShould
{
[Fact]
public void MultipleAssertions()
{
var testShoppingList = ShoppingListGenerator.GenerateItems();
testShoppingList.Should().NotBeNullOrEmpty();
testShoppingList.Should().Contain(new Item { Name = "Cheese", Quantity = 2 });
testShoppingList.Should().HaveCount(10);
testShoppingList.Should().OnlyHaveUniqueItems();
}
}
这种方法很好,但是查看我们的代码,我们可以看到这个测试会因为断言我们的列表将在 .Contain() 方法上失败,因为我们的列表中没有包含 Cheese 的项目。这个测试也会在我们的 .HaveCount() 方法上失败,因为我们的列表中只有 3 个项目,而不是 10 个。
让我们通过运行测试来确认我们的想法。
我们是对的!但是在这个例子中,我们的测试不仅对我们的 .Contains() 方法失败了,而且它已经停止运行我们的测试!
想象一下,我们修复了这个错误,使得断言通过,但在下一个断言中失败。然后是下一个,然后是下一个,依此类推。
像这样测试我们的代码会相当乏味。幸运的是,我们可以使用 Assertion Scope 来解决这个问题!
使用 Assertion Scopes,我们可以将多个断言批处理到一个 AssertionScope 中,这样 FluentAssertions 只会在所有失败的作用域结束时抛出一个异常。
让我们更改我们的测试以使用 Assertion Scope。
using AssertionScopes;
using FluentAssertions;
using FluentAssertions.Execution;
using System;
using Xunit;
namespace Tests
{
public class ShoppingListGeneratorShould
{
[Fact]
public void MultipleAssertions()
{
var testShoppingList = ShoppingListGenerator.GenerateItems();
using (new AssertionScope())
{
testShoppingList.Should().NotBeNullOrEmpty();
testShoppingList.Should().Contain(new Item { Name = "Cheese", Quantity = 2 });
testShoppingList.Should().HaveCount(10);
testShoppingList.Should().OnlyHaveUniqueItems();
}
}
}
}
我们现在将我们的断言包装在 using 语句中,并且我们的异常只会在处置我们的 AssertionScope 时被抛出。
让我们运行测试,看看会发生什么!
我们的测试失败了,但现在我们将两个异常都抛给了我们!
Message:
Expected testShoppingList {AssertionScopes.Item
{
Name = "Apple"
Quantity = 5
}, AssertionScopes.Item
{
Name = "Banana"
Quantity = 1
}, AssertionScopes.Item
{
Name = "Orange"
Quantity = 3
}} to contain
AssertionScopes.Item
{
Name = "Cheese"
Quantity = 2
}.
Expected testShoppingList to contain 10 item(s), but found 3.
现在,不必每次测试中的断言失败时都运行并重新运行我们的测试,我们可以立即查看测试中失败的所有断言!
结论
Fluent Assertions 是一个很棒的库,它允许我们以更自然和更有表现力的方式编写 C# 测试。Assertion Scopes 通过在找出测试失败的原因时节省我们的时间和精力,让我们在单元测试中使用多个断言时变得更轻松。
如果您想了解有关 Fluent 断言的更多信息,请在此处查看文档:https ://fluentassertions.com/about/