2009-10-26 7 views
8

今日私はNUnitで次の問題に遭遇しました。NUnitのIs.EqualToは、ジェネリッククラスから派生したクラスに対して確実に機能しませんか?

私はジェネリッククラスから派生したクラスを持っています。 私はいくつかのシリアル化テストを行い、NUnitのIs.EqualTo()関数を使って同等性をテストしました。

私は何かが間違っていると疑われ始めました。テストが失敗したはずです。代わりにobj1.Equals(obj2)を使用したときに失敗しました。私は次のテストを作成し調査するために

:第二の試験では(実際には矛盾がアサート)

namespace NUnit.Tests 

{ 

using Framework; 

    public class ThatNUnit 
    { 
     [Test] 
     public void IsNotEqualTo_ClientsNotEqual_Passes() 
     { 
      var client1 = new DerrivedClient(); 
      var client2 = new DerrivedClient(); 

      client1.Name = "player1"; 
      client1.SomeGenericProperty = client1.Name; 
      client2.Name = "player2"; 
      client2.SomeGenericProperty = client2.Name; 

      Assert.That(client1.Equals(client2), Is.False); 
      Assert.That(client1, Is.Not.EqualTo(client2)); 
     } 

     [Test] 
     public void IsNotEqualTo_ClientsAreEqual_AlsoPasses_SomethingWrongHere() 
     { 
      var client1 = new DerrivedClient(); 
      var client2 = new DerrivedClient(); 

      client1.Name = "player1"; 
      client1.SomeGenericProperty = client1.Name; 
      client2.Name = client1.Name; 
      client2.SomeGenericProperty = client1.Name; 

      Assert.That(client1.Equals(client2), Is.True); 
      Assert.That(client1, Is.Not.EqualTo(client2)); 
     } 
    } 

    public class DerrivedClient : Client<string> 
    { 
    } 

    public class Client<T> 
    { 
     public string Name { get; set; } 

     public T SomeGenericProperty { get; set; } 

     public override bool Equals(object obj) 
     { 
      if (ReferenceEquals(null, obj)) 
      { 
       return false; 
      } 
      if (ReferenceEquals(this, obj)) 
      { 
       return true; 
      } 
      if (obj.GetType() != typeof(Client<T>)) 
      { 
       return false; 
      } 
      return Equals((Client<T>)obj); 
     } 

     public bool Equals(Client<T> other) 
     { 
      if (ReferenceEquals(null, other)) 
      { 
       return false; 
      } 
      if (ReferenceEquals(this, other)) 
      { 
       return true; 
      } 
      return Equals(other.Name, Name) && Equals(other.SomeGenericProperty, SomeGenericProperty); 
     } 

     public override int GetHashCode() 
     { 
      unchecked 
      { 
       return ((Name != null ? Name.GetHashCode() : 0) * 397)^SomeGenericProperty.GetHashCode(); 
      } 
     } 

     public override string ToString() 
     { 
      return string.Format("{0}, {1}", Name, SomeGenericProperty); 
     } 
    } 
} 

2は、問題を示しています

Assert.That(client1.Equals(client2), Is.True); 
Assert.That(client1, Is.Not.EqualTo(client2)); 

このテストでは、一つの方法または他のを失敗しますしかし、それはしません!

私はNUnitのソースコードを少し掘り下げましたが、いくつかの特別な条件のためにいくつかのif()を実行した後、ObjectAreEqual(オブジェクトx、オブジェクトy)メソッド(最終的にAssert.That私は今Is.EqualToは()だけ長いルートを取ることを、考えなければならないので、私は、それは非常に当惑見つける

return x.Equals(y); 

、しかし:(X、Is.EqualTo(Y))は、このコード行に来ます基本的にはx.Equals(y)と同じようにしてください。

NUNit.Framework.Constraintsネームスペース内で興味のある人のための完全な方法:

public bool ObjectsEqual(object x, object y) 
    { 
     this.failurePoints = new ArrayList(); 

     if (x == null && y == null) 
      return true; 

     if (x == null || y == null) 
      return false; 

     Type xType = x.GetType(); 
     Type yType = y.GetType(); 

     if (xType.IsArray && yType.IsArray && !compareAsCollection) 
      return ArraysEqual((Array)x, (Array)y); 

     if (x is ICollection && y is ICollection) 
      return CollectionsEqual((ICollection)x, (ICollection)y); 

     if (x is IEnumerable && y is IEnumerable && !(x is string && y is string)) 
      return EnumerablesEqual((IEnumerable)x, (IEnumerable)y); 

     if (externalComparer != null) 
      return externalComparer.ObjectsEqual(x, y); 

     if (x is string && y is string) 
      return StringsEqual((string)x, (string)y); 

     if (x is Stream && y is Stream) 
      return StreamsEqual((Stream)x, (Stream)y); 

     if (x is DirectoryInfo && y is DirectoryInfo) 
      return DirectoriesEqual((DirectoryInfo)x, (DirectoryInfo)y); 

     if (Numerics.IsNumericType(x) && Numerics.IsNumericType(y)) 
      return Numerics.AreEqual(x, y, ref tolerance); 

     if (tolerance != null && tolerance.Value is TimeSpan) 
     { 
      TimeSpan amount = (TimeSpan)tolerance.Value; 

      if (x is DateTime && y is DateTime) 
       return ((DateTime)x - (DateTime)y).Duration() <= amount; 

      if (x is TimeSpan && y is TimeSpan) 
       return ((TimeSpan)x - (TimeSpan)y).Duration() <= amount; 
     } 

     return x.Equals(y); 
    } 

ここで何が起こっていて、どのように修正できますか?

私は自分のテストを信頼できるようにしたいので、必ずNUnitを再度実行してください。

また、Is.EqualTo()の代わりにEquals()を使用したいと考えています(前者は、テストが失敗したときに素晴らしい出力を得られません)。

ありがとうございます。

アップデート:私はこの問題に取り組んさらに、同様の問題hereを発見し、可能workaroundを投稿一方

答えて

5

問題は、第二の試験の第二のアサーションがClient<T>ではなくobjectを受け入れEqualsオーバーロードを呼び出すことであるので、この比較はfalseを返します。

// obj.GetType() returns Client.DerrivedClient 

if (obj.GetType() != typeof(Client<T>)) 
{ 
    return false; 
} 

この問題を解決するには、比較を変更することができますこれまでの操作:

if (obj.GetType() != this.GetType()) 
+0

ありがとうございましたJeff、これは正しい軌道にあるようです。 私の単純な例はそのように修正されましたが、実際のケースではまだ苦労しています。 これは、将来的には、生成されたコードの妥当性を認めるだけでなく、私に教えてくれるでしょう。 –

+0

私の喜び - 実際のケースは深刻な痛みだと思います。私の唯一のアドバイスは休憩を取ることです(短いものでも!)ので、あなたは新鮮な目でそれを見ることができます。がんばろう! –

関連する問題