4 Stimmen

MbUnit: Vergleich unterschiedlicher Objektinstanzen

Ich möchte wissen, ob es eine Möglichkeit gibt, zwei Objekte in MBUnit zu vergleichen, so dass der Test bestanden wird, wenn die Objekte "aussehen" die gleichen, auch wenn diese unterschiedliche Instanzen sind?

Zum Beispiel:

[TestFixture]
class ComparisonTestFixture
{

    class foo
       {
           public string bar;
       }

    [Test]
    public void ComparisonTest()
    {

        foo foo1 = new foo()
           {
               bar = "baz"
           };

        foo foo2 = new foo()
            {
                bar = "baz"
            };

        //This assertion should be successful, but it isn't
        //*** Failures ***
        //Expected values to be equal.
        //Expected Value & Actual Value : {foo: bar = "zzz...."}
        //Remark : Both values look the same when formatted but they are distinct instances.
        Assert.AreEqual(foo1,foo2);
    }
}

Assert.AreEqual() funktioniert in diesem Fall nicht (Test schlägt fehl, siehe Quellcode oben). Da es bemerkt, dass "beide Werte gleich aussehen, wenn formatiert, aber sie sind unterschiedliche Instanzen", ich denke, es muss eine Möglichkeit, dies zu tun, die in MbUnit bereits ohne Serialisierung der Objekte zu XML in meinem eigenen Code gebaut werden.

Muss ich dafür meine eigene Assert-Erweiterungsmethode schreiben?

7voto

Jeff Brown Punkte 1178

Yann hat auch einen StructuralEqualityComparer implementiert, der die Eigenschaftswerte anhand einer Reihe von Lambdas für jede Eigenschaft einzeln vergleicht. Ein Blick lohnt sich.

Mehr Informationen hier: http://www.gallio.org/api/html/T_MbUnit_Framework_StructuralEqualityComparer_1.htm

0 Stimmen

Jawohl. Wie Jeff sagt, ist der strukturelle Gleichheitsvergleicher das richtige Werkzeug, um in diesem Fall verwendet zu werden. Mehrere Assertions akzeptieren ein IEqualityComparer<T>-Objekt als Parameter (AreEqual, AreElementsEqual, etc.), der Comparer gibt der Assertion an, wie Typen zu vergleichen sind, die nicht explizit gleichwertig sind. Assert.AreEqual(foo1, foo2, new StructuralEqualityComparer<Foo> { { x => x.bar } });

0 Stimmen

Ein einfaches Anwendungsbeispiel finden Sie auch hier: interfacingreality.blogspot.com/2009/06/

0 Stimmen

Sieht nett aus, ist aber für meine Zwecke etwas übertrieben. Ich werde stattdessen einen EqualityComparer mit Reflexion verwenden. Dennoch, danke für den Hinweis!

4voto

Mauricio Scheffer Punkte 97391

Es gibt eine Überlastung von Assert.AreEqual() die eine IEqualityComparer<T> als Parameter und eine weitere, die eine EqualityComparison<T>

Andernfalls könnten Sie Folgendes verwenden Assert.AreEqual(Assert.XmlSerialize(a), Assert.XmlSerialize(b))

0 Stimmen

Ja, aber wo liegt der Vorteil? Ich müsste immer noch mein eigenes EqualityComparioson-Objekt implementieren. Ich sehe keinen Vorteil darin, equals zu überladen oder eine Erweiterungsmethode zu Assert hinzuzufügen.

0 Stimmen

Die zweite Möglichkeit habe ich auch schon ausprobiert. In den meisten Fällen funktioniert sie gut, aber die Serialisierung schlägt bei einigen weiteren Objekten fehl, da Ninject im Hintergrund verwendet wird. Das ist, was machte mich diesen Thread starten.

1voto

Martin Liversage Punkte 100306

Ich würde vorschlagen, dass Sie die Equals Methode in Ihrer Klasse, um den gewünschten Vergleich durchzuführen. Auf diese Weise können Sie Wertgleichheit anstelle von Referenzgleichheit definieren. Ein Nachteil ist, dass Sie auch die Methode GetHashCode wenn Sie überschreiben Equals um sicherzustellen, dass zwei Objekte, die gleich sind, auch den gleichen Hash-Code zurückgeben. Hier ist ein sehr einfaches Beispiel;

public class Foo {

  public String Bar {
    get;
    set;
  }

  public String Baz {
    get;
    set;
  }

  public override Boolean Equals(Object other) {
    Foo otherFoo = other as Foo;
    return otherFoo != null
      && Bar.Equals(otherFoo.Bar)
      && Baz.Equals(otherFoo.Baz);
  }

  public override Int32 GetHashCode() {
    return Bar.GetHashCode() ^ Baz.GetHasCode();
  }

}

Wenn Sie nicht überschreiben wollen Equals und Sie wirklich nur Instanzen Eigenschaft für Eigenschaft vergleichen wollen, können Sie Reflection verwenden:

public static Boolean AreEqual<T>(T a, T b) {
  foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
    if (!Object.Equals(propertyInfo.GetValue(a, null),
                       propertyInfo.GetValue(b, null)))
      return false;
  return true;
}

0 Stimmen

Aber das wäre nicht generisch. Ich müsste dies für jede neue Klasse, die ich teste, tun.

0 Stimmen

Aber offensichtlich verwendet Ihre Klasse Wertgleichheit und nicht Referenzgleichheit. Um diese Tatsache zu erfassen, sollten Sie wirklich in Erwägung ziehen, Folgendes zu überschreiben Equals . Davon können nicht nur Ihre Tests, sondern auch Ihr Anwendungscode profitieren.

0 Stimmen

In meiner aktuellen Anwendung muss ich nicht zwei Instanzen dieses Objekttyps vergleichen. Wenn ich Equals überschreiben würde, wäre das nur für Unit-Tests gedacht. Ich möchte den Overhead-Code für Unit-Tests auf ein Minimum beschränken.

1voto

Yuval Roth Punkte 1724

Was ich in der Regel tun, ist nur die ToString()-Überschreibung implementieren - die als beste Praxis zu tun, sowieso ist.

In Ihrem Fall also :

public override string ToString()
{
    return string.Format("Class foo, bar={0}",bar);
}

dann Ihr AreEqual(foo1,foo2) meldet tatsächlich die richtigen Ergebnisse, da es nur die Standardimplementierung von ToString aufruft

0 Stimmen

Das funktioniert zwar, hat aber den gleichen Nachteil wie das Überschreiben von Equals. Es ist nicht generisch, sondern erfordert zusätzlichen Code für jeden neuen Objekttyp, der verglichen werden soll.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X