簡體   English   中英

Fluent Assertions:近似比較兩個二維矩形數組

[英]Fluent Assertions: Approximately compare two 2D rectangular arrays

我能夠大致比較 Fluent Assertions 中的兩個二維矩形數組,如下所示:

float precision = 1e-5f;
float[,] expectedArray = new float[,] { { 3.1f, 4.5f}, { 2, 4} };
float[,] calculatedArray = new float[,] { { 3.09f, 4.49f}, { 2, 4} };

for (int y = 0; y < 2; ++y)
{
    for (int x = 0; x < 2; ++x)
    {
        calculatedArray[y,x].Should().BeApproximately(expectedArray[y,x], precision);
    }
}

但是有沒有更干凈的方法來實現這一點(沒有 for 循環)? 例如,與此相同的內容(用於一維數組):

double[] source = { 10.01, 8.01, 6.01 };
double[] target = { 10.0, 8.0, 6.0  };

source.Should().Equal(target, (left, right) => Math.Abs(left-right) <= 0.01);

一維數組的上述解決方案來自以下問題: Fluent Assertions: Compare two numeric collection大約

目前框架中似乎沒有任何東西支持這一點。 如果您不想在測試中使用循環,那么您可以選擇添加自己的擴展來覆蓋這種情況。

這有兩個要素。 第一個是添加一個擴展方法,為 2D 數組添加Should能力:

public static class FluentExtensionMethods
{
    public static Generic2DArrayAssertions<T> Should<T>(this T[,] actualValue)
    {
        return new Generic2DArrayAssertions<T>(actualValue);
    }
}

然后,您需要實現實際的斷言類,該類將包含比較循環:

public class Generic2DArrayAssertions<T> 
{
    T[,] _actual;

    public Generic2DArrayAssertions(T[,] actual)
    {
        _actual = actual;
    }

    public bool Equal(T[,] expected, Func<T,T, bool> func)
    {
        for (int i = 0; i < expected.Rank; i++)
            _actual.GetUpperBound(i).Should().Be(expected.GetUpperBound(i), 
                                                 "dimensions should match");

        for (int x = expected.GetLowerBound(0); x <= expected.GetUpperBound(0); x++)
        {
            for (int y = expected.GetLowerBound(1); y <= expected.GetUpperBound(1); y++)
            {
                func(_actual[x, y], expected[x, y])
                     .Should()
                     .BeTrue("'{2}' should equal '{3}' at element [{0},{1}]",
                      x, y, _actual[x,y], expected[x,y]);
            }
        }

        return true;
    }
}

然后,您可以像其他斷言一樣在測試中使用它:

calculatedArray.Should().Equal(expectedArray, 
                               (left,right)=> Math.Abs(left - right) <= 0.01);

我認為您的評論是在詢問您如何測試我建議的擴展代碼。 答案是,與測試其他任何東西的方式相同,傳遞值並驗證輸出。 我在下面添加了一些測試(使用 Nunit)來涵蓋一些關鍵場景。 需要注意的是,場景的數據是不完整的(它似乎超出了范圍並且不難生成)。 測試使用的是left == right的函數,因為重點是測試擴展,而不是近似值的評估。

[TestCaseSource("differentSizedScenarios")]
public void ShouldThrowIfDifferentSizes(float[,] actual, float[,] expected)
{
    Assert.Throws<AssertionException>(()=>actual.Should().Equal(expected, (l, r) => l == r)).Message.Should().Be(string.Format("Expected value to be {0} because dimensions should match, but found {1}.", expected.GetUpperBound(0), actual.GetUpperBound(0)));
}

[TestCaseSource("missMatchedScenarios")]
public void ShouldThrowIfMismatched(int[,] actual, int[,] expected, int actualVal, int expectedVal, string index)
{
    Assert.Throws<AssertionException>(()=>actual.Should().Equal(expected, (l, r) => l.Equals(r))).Message.Should().Be(string.Format("Expected True because '{0}' should equal '{1}' at element [{2}], but found False.", actualVal, expectedVal, index));
}

[Test]
public void ShouldPassOnMatched()
{
    var expected = new float[,] { { 3.1f, 4.5f }, { 2, 4 } };
    var actual = new float[,] { { 3.1f, 4.5f }, { 2, 4 } };
    actual.Should().Equal(expected, (l, r) => l.Equals(r));
}

static object[] differentSizedScenarios = 
{
    new object[] {
        new float[,] { { 3.1f, 4.5f }, { 2, 4 } },
        new float[,] { { 3.1f, 4.5f }, { 2, 4 }, {1,2} }
    },
    new object[] {
        new float[,] { { 3.1f, 4.5f }, { 2, 4 } },
        new float[,] { { 3.1f, 4.5f }}
    }
    // etc...
};
static object[] missMatchedScenarios = 
{
    new object[] {
        new int[,] { { 1, 2}, { 3, 4 } },
        new int[,] { { 11, 2}, { 3, 4 } }
        ,1, 11, "0,0"
    },
    new object[] {
        new int[,] { { 1, 2}, { 3, 14 } },
        new int[,] { { 1, 2}, { 3, 4 } }
        ,14, 4, "1,1"
    },
    // etc...
};

我還沒有完全測試過這個,但以下似乎有效。

float precision = 0.1f; // Test passes with this level of precision.
//float precision = 0.01f; // Test fails with this level of precision.
float[,] expectedArray = new float[,] { { 3.1f, 4.5f }, { 2, 4 } };
float[,] calculatedArray = new float[,] { { 3.09f, 4.49f }, { 2, 4 } };

calculatedArray.Should().BeEquivalentTo(
    expectedArray,
    options => options
        .ComparingByValue<float>()
        .Using<float>(ctx => ctx.Subject.Should().BeApproximately(ctx.Expectation, precision))
        .WhenTypeIs<float>());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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