Fluent Assertions 簡介
Fluent Assertions 是一個第三方套件,是一個斷言框架 (assertion framework),指在讓測試程式碼更容易閱讀、提供更容易除錯的測試失敗訊息。支援多種測試框架,包含 MSTest2, xUnit2, NUnit3, MSpec 和 NSpec3, 並且在 Json.NET, Ninject, Autofac, ASP.NET MVC, ASP.NET Core MVC 上也有特別支援的套件可以使用。
原本的測試程式碼
筆者平時在寫 C# 的單元測試時,都是使用 NUnit 測試框架,先來看一段很簡單的測試:
[Test]
public void Test1()
{
const int input1 = 1;
const int input2 = 2;
const int expected = 3;
Assert.AreEqual(expected, input1 + input2);
}
上面這段程式碼在 Rider 開發工具中會有建議提示:
Consider using the constraint model, Assert.That(actual, Is.EqualTo(expected)), instead of the classic model, Assert.AreEqual(expected, actual)
意思是指 Assert.AreEqual 是經典模型(classic model),叫我們可以替換為 Assert.That 的約束模型(constraint model)
兩者的比較如下:
// 經典模型
Assert.AreEqual(expected, input1 + input2);
// 約束模型
Assert.That(input1 + input2, Is.EqualTo(expected));
在 StackOverflow 上也有人在討論這兩種的方式,筆者比較喜歡經典模型,不過不管哪種方式似乎都不太容易閱讀
安裝 Fluent Assertions
使用 NuGet 安裝 FluentAssertions 套件,或是使用 .NET CLI 指令安裝:
dotnet add package FluentAssertions
使用 Fluent Assertions 的測試程式碼
回到上面的範例,看一下使用 Fluent Assertions 後的測試程式碼:
[Test]
public void Test1()
{
const int input1 = 1;
const int input2 = 2;
const int expected = 3;
// 經典模型
Assert.AreEqual(expected, input1 + input2);
// 約束模型
Assert.That(input1 + input2, Is.EqualTo(expected));
// 使用 Fluent Assertions
(input1 + input2).Should().Be(expected);
}
Fluent Assertions 示範
[Test]
public void Test2()
{
// 比對文字
var userNames = "testUser01";
// 錯誤示範,錯誤訊息: Expected userNames to be "Ruyut" with a length of 5, but "testUser01" has a length of 10, differs near "tes" (index 0).
// userNames.Should().Be("Ruyut");
// 正確:
userNames.Should().Be("testUser01");
// 例外捕捉
Action action = () => { throw new Exception("this is a exception"); };
// 錯誤示範,錯誤訊息: Expected exception message to match the equivalent of "this is a exception!!!", but "this is a exception" does not.
// action.Should().Throw<Exception>().WithMessage("this is a exception!!!");
// 正確:
action.Should().Throw<Exception>().WithMessage("this is a exception");
// 比對集合
IEnumerable<int> numbers = new[] { 1, 2, 3 };
// 錯誤示範,錯誤訊息: Expected numbers to contain only items matching (n == 0), but {1, 2, 3} do(es) not match.
// numbers.Should().OnlyContain(n => n == 0); // 正確: numbers.Should().OnlyContain(n => n > 0);
// 正確:
numbers.Should().OnlyContain(n => n > 0);
// 比對日期時間
var dateTime = new DateTime(2022, 1, 1, 20, 30, 0);
// 錯誤示範,錯誤訊息: Expected the seconds part of dateTime to be 30, but found 0.
// dateTime.Should().HaveYear(2022).And.HaveMonth(1).And.HaveDay(1).And.HaveHour(20).And.HaveMinute(30).And.HaveSecond(30);
// 正確寫法 1:
dateTime.Should().Be(new DateTime(2022, 1, 1, 20, 30, 0));
// 正確寫法 2:
dateTime.Should().HaveYear(2022).And.HaveMonth(1).And.HaveDay(1).And.HaveHour(20).And.HaveMinute(30).And.HaveSecond(0);
// 比對列舉
TestEnum testEnum = TestEnum.Test1;
// 錯誤示範,錯誤訊息: Expected testEnum to be TestEnum.Test2 {value: 1}, but found TestEnum.Test1 {value: 0}.
// testEnum.Should().Be(TestEnum.Test2);
// 正確:
testEnum.Should().Be(TestEnum.Test1);
// 其他示範
testEnum.Should().HaveValue(0);
((TestEnum)2).Should().BeDefined();
((TestEnum)3).Should().NotBeDefined(); // 因為只有到 2
}
public enum TestEnum
{
Test1 = 0,
Test2,
Test3,
}
在開始使用 Fluent Assertions 寫測試之後,筆者覺得程式碼的可讀性有變高,程式碼也有變簡潔,同個變數要加上多個測試內容也可以很方便的使用 And 連接即可,非常推薦大家使用 Fluent Assertions
參考資料:
Fluent Assertions
FluentAssertions - GitHub
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com