web-dev-qa-db-ja.com

C#-ユニットテストで2つのオブジェクトが等しいことをアサートする

NunitまたはMicrosoft.VisualStudio.TestTools.UnitTestingを使用します。現在、私の主張は失敗しています。

    [TestMethod]
    public void GivenEmptyBoardExpectEmptyBoard()
    {
        var test = new Board();

        var input = new Board()
            {
                Rows = new List<Row>()
                    {
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                    }
            };

        var expected = new Board()
        {
            Rows = new List<Row>()
                    {
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                    }
        };

        var lifeOrchestration = new LifeOrchestration();

        var actual = lifeOrchestration.Evolve(input);

        Assert.AreEqual(expected, actual);
    }
16

2つの異なるBoardインスタンスがあるため、Assert.AreEqualへの呼び出しは失敗します。内容全体が同じに見える場合でも、基になる値ではなく、参照を比較しています。

2つのBoardインスタンスを等しくするものを指定する必要があります。

テストでそれを行うことができます:

Assert.AreEqual(expected.Rows.Count, actual.Rows.Count);
Assert.AreEqual(expected.Rows[0].Cells[0], actual.Rows[0].Cells[0]);

// Lots more tests of equality...

または、あなたのクラスでそれを行うことができます:(その場で書いたことに注意してください-あなたはこれを調整したいでしょう)

public class Board
{
    public List<Row> Rows = new List<Row>();

    public override bool Equals(object obj)
    {
        var board = obj as Board;

        if (board == null)
            return false;

        if (board.Rows.Count != Rows.Count)
            return false;

        return !board.Rows.Where((t, i) => !t.Equals(Rows[i])).Any();
    }

    public override int GetHashCode()
    {
        // determine what's appropriate to return here - a unique board id may be appropriate if available
    }
}

public class Row
{
    public List<int> Cells = new List<int>(); 

    public override bool Equals(object obj)
    {
        var row = obj as Row;

        if (row == null)
            return false;

        if (row.Cells.Count != Cells.Count)
            return false;

        if (row.Cells.Except(Cells).Any())
            return false;

        return true;
    }

    public override int GetHashCode()
    {
        // determine what's appropriate to return here - a unique row id may be appropriate if available
    }
}
18
Grant

以前はgetHasCodeとequalsをオーバーライドしていましたが、単体テストのために実動コードを変更したくないので、それは好きではありませんでした。また、それは一種の痛みです。

それから私はあまりにも侵襲的ではないオブジェクトを比較するために反射しすぎました...しかし、それは一種の多くの仕事です(多くのコーナーケース)

最終的に私は使用します:

http://www.nuget.org/packages/DeepEqual/

よく働く。

10
foobarcode

依存関係を追加する必要がなく、VS単体テストで動作し、2つのオブジェクトのフィールド値を比較し、等しくないフィールドをすべて教えてくれるソリューションが必要でした。これが私が思いついたものです。プロパティ値でも機能するように拡張できることに注意してください。

私の場合、これはいくつかのファイル解析ロジックの結果を比較して、2つの技術的に「異なる」エントリに同じ値のフィールドがあることを確認するのに役立ちます。

    public class AssertHelper
    {
        public static void HasEqualFieldValues<T>(T expected, T actual)
        {
            var failures = new List<string>();
            var fields = typeof(T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            foreach(var field in fields)
            {
                var v1 = field.GetValue(expected);
                var v2 = field.GetValue(actual);
                if (v1 == null && v2 == null) continue;
                if(!v1.Equals(v2)) failures.Add(string.Format("{0}: Expected:<{1}> Actual:<{2}>", field.Name, v1, v2));
            }
            if (failures.Any())
                Assert.Fail("AssertHelper.HasEqualFieldValues failed. " + Environment.NewLine+ string.Join(Environment.NewLine, failures));
        }
    }

    [TestClass]
    public class AssertHelperTests
    {
        [TestMethod]     
        [ExpectedException(typeof(AssertFailedException))]           
        public void ShouldFailForDifferentClasses()
        {            
            var actual = new NewPaymentEntry() { acct = "1" };
            var expected = new NewPaymentEntry() { acct = "2" };
            AssertHelper.HasEqualFieldValues(expected, actual);
        }
    }
7
Daniel

ExpectedObjects は、プロパティ値による同等性の比較に役立ちます。以下をサポートします。

  1. 単純なオブジェクト:expected.ToExpectedObject()。ShouldEqual(actual);
  2. コレクション:expected.ToExpectedObject()。ShouldEqual(actual);
  3. 構成されたオブジェクト:expected.ToExpectedObject()。ShouldEqual(actual);
  4. 部分比較:予想されるオブジェクトは匿名型で設計する必要があり、expected.ToExpectedObject()。ShouldMatch(actual)を使用する

オブジェクトの等価性を比較するための2つのAPIを呼び出すだけでよいため、ExpectedObjectsが大好きです。

  1. ShouldEqual()
  2. 部分比較用のShouldMatch()
7
In91

アサートメソッドは、オブジェクトのEqualsおよびGetHashcodeに依存します。あなたはそれを実装することができますが、単体テストの外でこのオブジェクトの平等が必要でない場合、代わりにオブジェクトの個々のプリミティブ型を比較す​​ることを検討します。オブジェクトは十分に単純で、equalsのオーバーライドは実際には保証されていないように見えます。

0
TGH

ドメインオブジェクト、DTO、またはエンティティなどの単純なオブジェクトの場合、両方のインスタンスを文字列にシリアル化し、その文字列を比較するだけで済みます。

var object1Json = JsonConvert.SerializeObject(object1);
var object2Json = JsonConvert.SerializeObject(object2);

Assert.AreEqual(object1Json, object2Json);

もちろん、これにはさまざまな注意事項があります。そのため、クラスのJSONに、比較する必要のある期待値が含まれているかどうかを評価してください。

たとえば、クラスにアンマネージリソースまたはシリアル化できないプロパティが含まれている場合、それらは適切に比較されません。また、デフォルトではパブリックプロパティのみをシリアル化します。

0
CodeCaster