[英]Testing Optional equivalence with FluentAssertions
我正在使用一個名為Optional
( https://github.com/nlkl/Optional ) 的庫,它允許函數式語言常見的“可能”抽象。
該庫很棒,但我在測試方面面臨一個問題:我無法正確測試 2 個可選實例是否等效。
為了測試等效性,我使用Fluent Assertions 。 但是,我沒有得到想要的結果。
我將用代碼說明問題:
#load "xunit"
[Fact]
void TestOptional()
{
var a = new[] { 1, 2, 3 }.Some();
var b = new[] { 1, 2, 3 }.Some();
a.Should().BeEquivalentTo(b);
}
這個測試失敗了,正如我在屏幕截圖中顯示的(為了方便,我正在使用 LINQPad)
如您所見,這不是人們所期望的。
我如何告訴 Fluent Assertions 使用 Option 類型正確檢查等效性?
我在 Github 上打開了一個關於你的問題的問題,昨天 合並了一個 拉取請求,所以下一個(預)發布應該能讓你優雅地解決你的問題:
新的重載允許您使用開放的泛型類型。 如果同時指定了開放類型和封閉類型,則封閉類型優先。
SelfReferenceEquivalencyAssertionOptions
添加了以下方法:
public TSelf ComparingByMembers(System.Type type) { }
public TSelf ComparingByValue(System.Type type) { }
這是添加到 Fluent Assertions 的單元測試,展示了它是如何工作的:
[Fact]
public void When_comparing_an_open_type_by_members_it_should_succeed()
{
// Arrange
var subject = new Option<int[]>(new[] { 1, 3, 2 });
var expected = new Option<int[]>(new[] { 1, 2, 3 });
// Act
Action act = () => subject.Should().BeEquivalentTo(expected, opt => opt
.ComparingByMembers(typeof(Option<>)));
// Assert
act.Should().NotThrow();
}
值類型
要確定 Fluent Assertions 是否應該遞歸到對象的屬性或字段中,它需要了解哪些類型具有值語義以及哪些類型應該被視為引用類型。 默認行為是將覆蓋 Object.Equals 的每個類型視為旨在具有值語義的對象。 不幸的是,匿名類型和元組也覆蓋了這個方法,但是因為我們傾向於在等價比較中經常使用它們,所以我們總是通過它們的屬性來比較它們。
您可以通過為各個斷言使用
ComparingByValue<T>
或ComparingByMembers<T>
選項輕松覆蓋它
Option<T>
是一個struct
並覆蓋Equals
,因此 Fluent Assertions 將a
和b
與值語義進行比較。
Option<T>
像這樣實現Equals
:
public bool Equals(Option<T> other)
{
if (!this.hasValue && !other.hasValue)
return true;
return this.hasValue
&& other.hasValue
&& EqualityComparer<T>.Default.Equals(this.value, other.value);
}
因此int[]
通過引用進行比較並且您的測試失敗。
您可以為每個測試單獨覆蓋此行為,就像Guro Stron所說:
a.Should().BeEquivalentTo(b, opt => opt.ComparingByMembers<Option<int[]>>());
或者通過靜態AssertionOptions
類全局:
AssertionOptions.AssertEquivalencyUsing(options =>
options.ComparingByMembers<Option<int[]>>());
編輯:
對於您的情況,Fluent Assertions 需要一個支持未綁定泛型類型的AssertEquivalencyUsing
覆蓋:
AssertionOptions.AssertEquivalencyUsing(options =>
options.ComparingByMembers(typeof(Option<>)));
不幸的是,不存在這樣的覆蓋。
提出的另一個解決方案是擴展方法。 這是一個非常簡單的實現:
public static class FluentAssertionsExtensions
{
public static void BeEquivalentByMembers<TExpectation>(
this ComparableTypeAssertions<TExpectation> actual,
TExpectation expectation)
{
actual.BeEquivalentTo(
expectation,
options => options.ComparingByMembers<TExpectation>());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.