語境:
我們需要使用具有許多排列的許多屬性來斷言物件回應,其中相當多的屬性是動態的(生成的 GUID 等)。
示例場景
使用 FluentAssertions 時...Should().BeEquivalentTo(...),可以在一次評估中獲得所有不匹配欄位的串列。
所以給定(C#)代碼:
using System;
using FluentAssertions;
public class Program
{
public class HouseResponse
{
public int Windows { get; set; }
public int Bedrooms { get; set; }
public int Doors { get; set; }
public int Bathrooms { get; set; }
}
public static readonly HouseResponse ExpectedHouseResponse = new HouseResponse
{
Windows = 10,
Bedrooms = 5,
Doors = 2,
Bathrooms = 2
};
public static readonly HouseResponse ActualHouseResponse = new HouseResponse
{
Windows = 10,
Bedrooms = 5,
Doors = 3,
Bathrooms = 3
};
public static void Main()
{
ActualHouseResponse
.Should()
.BeEquivalentTo(ExpectedHouseResponse);
}
}
如果有 2 個屬性不匹配,則單個斷言的輸出為:
Unhandled exception. FluentAssertions.Execution.AssertionFailedException: Expected property root.Doors to be 2, but found 3.
Expected property root.Bathrooms to be 2, but found 3.
當您在一條錯誤訊息中獲得所有失敗時,這非常方便。
但是對于部分匹配,假設我們期望門的數量不同但始終是有效數字 > 0,我們將不得不這樣做:
public static void Main()
{
ActualHouseResponse
.Should()
.BeEquivalentTo(ExpectedHouseResponse, config =>
config.Excluding(x => x.Doors));
ActualHouseResponse.Doors.Should().BeGreaterThan(0);
}
這實際上不會命中ActualHouseResponse.Doors.Should().BeGreaterThan(0);斷言,因為我們已經失敗了,.Should().BeEquivalentTo因為.Bathrooms不匹配。
因此,目標是能夠一次性評估所有屬性。這將:
- 強制評估所有屬性。
- 允許我們在一次測驗運行中獲得所有失敗屬性的摘要(而不是必須修復一個屬性,運行測驗然后查看下一個失敗的位置等)
類似于以下內容:
public static void Main()
{
ActualHouseResponse
.Should()
.BeEquivalentTo(ExpectedHouseResponse, config =>
config.OverideEvaluation(x => x.Doors, doors => doors > 0));
}
有沒有人有任何想法或者偶然發現了一些我可能錯過的 FluentAssertions 檔案?
PS 我知道這可以通過自定義 RuleBuilder 完成,并且熟悉 FluentValidation,但希望將其保留為最后的手段。
uj5u.com熱心網友回復:
您可以使用Using/When組合來指示等效引擎如何比較某些屬性。
ActualHouseResponse.Should().BeEquivalentTo(ExpectedHouseResponse, opt => opt
.Using<int>(ctx => ctx.Subject.Should().BeGreaterThan(0))
.When(e => e.Path.EndsWith(nameof(HouseResponse.Doors)))
);
https://fluentassertions.com/objectgraphs/#equivalency-comparison-behavior
uj5u.com熱心網友回復:
我看到一種選擇是使用AssertionScope
public static void Main()
{
using (new AssertionScope())
{
ActualHouseResponse
.Should()
.BeEquivalentTo(ExpectedHouseResponse, config =>
config.Excluding(x => x.Doors));
ActualHouseResponse.Doors.Should().BeGreaterThan(0);
}
}
它將在停止執行之前運行所有斷言。
但這并不強制評估 ActualHouseResponse 的所有屬性。
uj5u.com熱心網友回復:
對于那些感興趣的人,這是我根據喬納斯的回答采用的解決方案
public static class EquivalencyAssertionOptionsExtensions
{
public static EquivalencyAssertionOptions<TSource> Override<TSource, TProperty>(
this EquivalencyAssertionOptions<TSource> options,
Expression<Func<TSource, TProperty>> propertyAccessor,
Action<TProperty> assertion)
{
var memberExpression = (MemberExpression) propertyAccessor.Body;
var propertyName = memberExpression.Member.Name;
return options
.Using<TProperty>(ctx => assertion(ctx.Subject))
.When(x => x.SelectedMemberPath.Equals(propertyName));
}
}
這讓我做
ActualHouseResponse.Should().BeEquivalentTo(ExpectedHouseResponse, opt => opt
.Override(x => x.Doors, doors => doors.Should().BeGreaterThan(0))
.Override(x => x.Windows, windows => windows.Should().BeLessThan(10))
);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/483083.html
