2009-07-16 6 views
1

私はいくつかのクラスによって実装されているジェネリックとのインターフェースを持っています。これらの各クラスには、インタフェースを実装するプロキシクラスもあります。私はこのような何かを見たいと思うジェネリックを使用するタイプから継承するユニットテスト

public interface ISomeInterface<T> 
{ 
    T SomeProperty 
    { 
     get; 
    } 

    T SomeAction(); 
} 

public interface IClassA : ISomeInterface<string> 
{ 
    void Action(); 
} 


public class ClassA : IClassA 
{ 
    // Code goes here 
} 

public class ClassAProxy : IClassA 
{ 
    // Code goes here 
} 

ユニットテストコード:

public abstract class ISomeInterfaceTests<T> 
{ 
    [TestMethod()] 
    public void SomePropertyTest() 
    { 
     ISomeInterface<T> target; 
     ISomeInterface<T> oracle; 
     this.CreateInstance(out target, out oracle); 

     Assert.AreEqual(oracle.SomeProperty, target.SomeProperty); 
    } 

    [TestMethod()] 
    public void SomeActionTest() 
    { 
     ISomeInterface<T> target; 
     ISomeInterface<T> oracle; 
     this.CreateInstance(out target, out oracle); 

     T oracleValue = oracle.SomeAction(); 
     T targetValue = target.SomeAction(); 

     Assert.AreEqual(oracleValue, targetValue); 
    } 

    // More tests 

    protected abstract void CreateInstance(out ISomeInterface<T> target, out ISomeInterface<T> oracle); 
} 

[TestClass()] 
public class ClassAProxyTests : ISomeInterfaceTests<string> 
{ 
    // ClassAProxy specific tests 

    protected override void CreateInstance(out ISomeInterface<string> target, out ISomeInterface<string> oracle) 
    { 
     // Create target as ClassAProxy here and oracle as ClassA 
    } 
} 

をしかし、これはエラーを与える: UTA002:TestClassを属性は、汎用クラスISomeInterfaceTestsに定義することはできません大体このコードを与えます<T>。

これにはすばらしい回避策がありますか?現在、私が考えることができる最高のソリューションは、ISomeInterfaceTestsの異なるテストメソッドを呼び出すClassAProxyTestsのメソッドを持つことです。<T>。

  • それはISomeInterfaceTests <T>を実施し、各テストのために手動で行う必要があります。しかしそのアプローチにはいくつかの問題があります。
  • 一方のメソッドがアサーションに失敗した場合、残りのメソッドは実行されません。
  • ExpectedException属性を使用することはできず、try catchステートメントで必要なコードをラップする必要があります。

しかし、もっと良い解決策が私を逃しています。

答えて

1

あなたがNUnit 2.5のGenericTestFixture機能を使用する必要があるような音。この機能を使用すると、汎用クラスに[TestFixture]属性を置き、テストフィクスチャのどの特殊化を適用するかを指定できます。

あなたの主なテスト・フィクスチャは、次のようになります(そして、あなたはあまりにもいくつかのインターフェイスを削除することができるかもしれ):

[TestFixture(typeof(string))] 
public class ClassAProxyTests<T> : ISomeInterfaceTests<T> where T: class 
{ 
    // Add ISomeInterfaceTests<T> methods here. 
    // ISomeInterfaceTests may no longer be required as the abstraction is defined in ClassAProxyTests. 

    // ClassAProxy specific tests 

    protected override void CreateInstance(out ISomeInterface<T> target, out ISomeInterface<string> oracle) 
    { 
     // Create target as ClassAProxy here and oracle as ClassA 
    } 
} 
+0

残念ながら、NUnitを使用することは、承認を得るためにかなりの数の赤いテープが必要になるため、この段階ではオプションではありません。 – Cornelius

0

親クラスを持つ唯一の理由は、インターフェイスのインスタンスを作成することです。

代わりにMOQを使用してください。

編集:

Not quite. The ISomeInterfaceTests<T> class is used to test the functionality of the proxies implementing the ISomeInterface<T> interface - it tests the proxies against the objects they are a proxy for (the oracle). – Cornelius

うーん...それは、統合テストのように聞こえます。あなたのOracleオブジェクトはデータベースから何らかの形で読み込まれていますか、そうでなければならないようにそれらを嘲笑していますか?とにかく、私はMoqを使ってあなたのインスタンスを取得し、一般的な対統合テストを嘲笑しています。

しかし、あなたのテストの一般化に対するあなたのアプローチが問題になるかもしれないと私は思います。おそらく別のアプローチですか?でこれを試してみてください:

public static class GenericISomeInterfaceTests 
{ 
    public static void SomePropertyTest<T>(ISomeInterface<T> target, ISomeInterface<T> oracle) 
    { 

     Assert.AreEqual(oracle.SomeProperty, target.SomeProperty); 
    } 

    public static void SomeActionTest<T>(ISomeInterface<T> target, ISomeInterface<T> oracle) 
    { 

     T oracleValue = oracle.SomeAction(); 
     T targetValue = target.SomeAction(); 

     Assert.AreEqual(oracleValue, targetValue); 
    } 

    // More tests 
} 

[TestClass()] 
public class ClassAProxyTests 
{ 
    [TestMethod] 
    public void SomePropertyStringTest() 
    { 
     // set up instances (using MOQ, or whatever) with the string generic type. 
     // Call them target and oracle 

     // then call your generic test methods 
     GenericISomeInterfaceTests.SomePropertyTest<string>(target, oracle); 
    } 

    [TestMethod] 
    public void SomeActionStringTest() 
    { 
     // set up instances (using MOQ, or whatever) with the string generic type. 
     // Call them target and oracle 

     // then call your generic test methods 
     GenericISomeInterfaceTests.SomeActionTest<string>(target, oracle); 
    } 
} 
+0

ないかなりの。 ISomeInterfaceTests <T>クラスは、ISomeInterface <T>インターフェイスを実装しているプロキシの機能をテストするために使用されます。プロキシは、プロキシ(オラクル)であるオブジェクトに対してテストされます。 – Cornelius

+0

oracleはモックアップ・オブジェクトであり、データベース作業は行いません。 提案した方法では、依然として、すべての異なるプロキシテストに対してテストメソッドを実装する必要があります。したがって、ClassBProxyTestsとClassCProxyTestsは、すべてのテストメソッドと関連する属性(TestMethod、ExpectedException)も明示的に指定する必要があります。 GenericISomeInterfaceTests(これは毎回テストを再実装するよりもはるかに優れています)を呼び出すだけですが、それが必要ない解決策が望ましいでしょう。 – Cornelius

+0

私はそのような解決策が存在するとは思わない。 TestMethodはすべてのテストメソッドの期間に必要です。 – Randolpho