簡體   English   中英

使用 FluentAssertions 測試可選的等效性

[英]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 - 對象圖比較說:

值類型

要確定 Fluent Assertions 是否應該遞歸到對象的屬性或字段中,它需要了解哪些類型具有值語義以及哪些類型應該被視為引用類型。 默認行為是將覆蓋 Object.Equals 的每個類型視為旨在具有值語義的對象 不幸的是,匿名類型和元組也覆蓋了這個方法,但是因為我們傾向於在等價比較中經常使用它們,所以我們總是通過它們的屬性來比較它們。

您可以通過為各個斷言使用ComparingByValue<T>ComparingByMembers<T>選項輕松覆蓋它

Option<T>是一個struct並覆蓋Equals ,因此 Fluent Assertions 將ab與值語義進行比較。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM