0

私は約このような流暢アサーション内の2つの2次元矩形アレイ比較することよ:流暢アサーション:約2次元矩形アレイを比較

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); 
    } 
} 

をこれを達成するためのクリーンな方法が存在する(ためのループ無し)? 1D配列は、質問から来ているため

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); 

上記溶液:例えば、(1次元アレイのためである)これと同じ調子で何かがFluent Assertions: Compare two numeric collections approximately

+0

あなたは[] [] '、むしろ' [、]フロート 'より' floatを使うことができるしている場合は、のようなもの持っているリンクの答えに展開することができます: 'expectedArray.Shouldを()。 ' – forsvarir

+0

(true、true);});}};}}};}}}; @forsvarir float [、]は行列の要素を保持するために使用されているので、この場合私の好みはぎざぎざの配列を使う代わりに長方形の配列を保持することです。そのような過負荷はそのように使用できることを知っておくことは良いことですが、 – Ayb4btu

答えて

1

何があるように表示されません。現在これをサポートするフレームワークにあります。テストでループを実行したくない場合は、このシナリオをカバーするために独自の拡張機能を追加するオプションがあります。

これには2つの要素があります。

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; 
    } 
} 

することができます:あなたはその後、比較ループが含まれています実際のアサーションクラスを実装する必要が

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

:最初は、2DアレイにShould能力を追加する拡張メソッドを追加することですその後、他のアサーションのようなあなたのテストでそれを使用する:

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... 
}; 
+0

それは素晴らしい解決策です。再帰的になるために、このコードが正しく動作することを保証する単体テストの記述方法がありますか?または、これはコードを手動でチェックする必要があるケースです(Fluentassertions failケースは、それを呼び出すユニットテストでAssertを打つ前に 'Generic2DArrayAssertions'を終了します)。 – Ayb4btu

+0

@ Ayb4btu拡張機能が動作することを検証する方法を尋ねていると思います。動作を検証するためのテストをいくつか追加しました。これがあなたの後ろでない場合は、あなたの質問を理解できません。 – forsvarir

+0

ええ、それは私が求めていたものでした。私はキャプチャし、フェイル・ケースのメッセージを処理する方法を知らなかったので、.Message.Should()。拡張子はかなりきれいです。偉大な答えをありがとう。 – Ayb4btu