SemanticComparison を使用したネストされたオブジェクトのプロパティの比較
-
21-12-2019 - |
質問
同じ型の 2 つのオブジェクトをメンバーごとに比較する必要がある単体テストを作成しています。カスタム比較コードを作成せずに、SemanticComparison ライブラリを使用してこのタスクを処理することにしました。フラットなオブジェクトを比較する場合には非常にうまく機能しますが、オブジェクトにメンバーごとの比較も必要なネストされたオブジェクトが含まれている場合には問題が発生します。
public class Outer
{
public string Name { get; set; }
public Inner Inner { get; set; }
}
public class Inner
{
public string Name { get; set; }
public string Value { get; set; }
}
public class Service
{
public Outer Method()
{
return new Outer()
{
Name = "outerName",
Inner = new Inner()
{
Name = "innerName",
Value = "value1"
}
};
}
}
内部オブジェクトはメンバーごとではなく参照によって比較されるため、これは機能しません。
[Test]
public void SimpleTest1()
{
// setup
var expectedLikeness = new Outer()
{
Name = "outerName",
Inner = new Inner()
{
Name = "innerName",
Value = "value1"
}
}.AsSource().OfLikeness<Outer>();
var sut = new Service();
// exercise sut
var actual = sut.Method();
// verify
expectedLikeness.ShouldEqual(actual);
}
これを機能させるには、デフォルトの等しい実装をオーバーライドするように、ネストされたオブジェクトのプロキシを作成する必要がありました。
[Test]
public void SimpleTest2()
{
// setup
var expectedLikeness = new Outer()
{
Name = "outerName",
Inner = new Inner()
{
Name = "innerName",
Value = "value1"
}.AsSource().OfLikeness<Inner>().CreateProxy()
}.AsSource().OfLikeness<Outer>();
var sut = new Service();
// exercise sut
var actual = sut.Method();
// verify
expectedLikeness.ShouldEqual(actual);
}
これは正しく動作しますが、サービス コードのリファクタリング後に、内部クラスの value プロパティが期待値と異なる原因となるバグが導入されたと想像してください。SemanticComparison の優れた機能は、不平等の原因となるメンバーの名前をログに記録できることです。ただし、この場合、不一致として「Inner」のみが返され、Inner クラスの特定のプロパティの名前は返されません。
何かが足りないのでしょうか?実際の不一致メンバーを返すことができるように構成することは可能ですか。
これは、この例のような単純なデータ構造では問題にならないことは明らかですが、実際のコードをテストする場合には不都合になる可能性があります。
解決
誰も答えてくれなかったので、私なりの答えを書きます。
したがって、追加のコードを書かない限り、OOTB で実行することはできないようです。コードを拡張メソッドのセットにラップしました。これらのメソッドを使用すると、参照ではなく内部類似性を使用して、どの内部プロパティ/コレクション プロパティを比較する必要があるかを指定できます。プロキシを手動で作成する必要はありません。すべてはこれらの拡張機能によって内部で処理されます。また、すべての内部比較の結果がログに記録されるため、どのメンバーに無効な値があるかを正確に確認できます。
これは、「WithInnerLikeness」拡張メソッドを使用した質問のテストです。
[Test]
public void ServiceTest3()
{
// setup
var expected = new Outer()
{
Name = "outerName",
Inner = new Inner()
{
Name = "innerName",
Value = "value2"
}
};
var expectedLikeness = expected.AsSource().OfLikeness<Outer>()
.WithInnerLikeness(d => d.Inner, s => s.Inner)
;
var sut = new Service();
// exercise sut
var actual = sut.Method();
// verify
expectedLikeness.ShouldEqual(actual);
}
内部オブジェクトの値プロパティが一致しないことがわかり、テストは失敗するはずです。そして、出力に次のメッセージが表示されて失敗します。
Comparing inner properties using likeness. Source: s => s.Inner Destination: d => d.Inner.
The source and destination values are not equal. Details: The provided value ClassLibrary1.Inner did not match the expected value ClassLibrary1.Inner. The following members did not match:
- Value.
Ploeh.SemanticComparison.LikenessException : The provided value ClassLibrary1.Outer did not match the expected value ClassLibrary1.Outer. The following members did not match:
- Inner.
ソース コードとその他の例は github で見つけることができます。