インターフェイスの実装をテストするために、一連の再利用可能なテストを実装できますか?
-
28-10-2019 - |
質問
私はC#で一連のコレクションクラスを執筆しており、それぞれが同様のカスタムインターフェイスを実装しています。インターフェイスの単一テストのコレクションを1つのコレクションを作成し、いくつかの異なる実装ですべてを自動的に実行することは可能ですか?実装ごとに複製されたテストコードを避けたいと思います。
これを達成するために、どんなフレームワーク(ヌニットなど)またはビジュアルスタジオ拡張機能を調べることをいとわない。
同じことをしたい人のために、私は具体的なソリューションを投稿しました。 Avandeursenの受け入れられたソリューション, 、 なので 答え.
解決
はい、それは可能です。トリックは、ユニットクラスのテスト階層をコードのクラス階層に従うことです。
インターフェイスがあると仮定しましょう Itf
クラスの実装 C1
と C2
.
最初にテストクラスを作成します Itf
(ItfTest
)。実際にテストを行使するには、あなたの模擬実装を作成する必要があります Itf
インターフェース。
これのすべてのテスト ItfTest
の実装を渡す必要があります Itf
(!)。そうでない場合、あなたの実装は リスコフ代替原則 (マーティンの「L」 個体 OOデザインの原則)
したがって、テストケースを作成します C1
, 、 君の C1Test
クラスは拡張できます ItfTest
. 。あなたの拡張機能は、模擬オブジェクトの作成をの作成に置き換える必要があります C1
オブジェクト(それを注入する、またはaを使用します GOFファクトリーメソッド)。このように、すべて ItfTest
ケースはタイプのインスタンスに適用されます C1
. 。さらに、あなた C1Test
クラスには、固有の追加のテストケースを含めることができます C1
.
同様に C2
. 。そして、より深いネストされたクラスとインターフェイスのためにトリックを繰り返すことができます。
参照:バインダー 多型サーバーテスト パターン、およびマクレガー 協定 - コンポーネントテスト用の並列アーキテクチャ。
他のヒント
拡張 ジョー 回答、nunitの[testcasesource]属性をMbunitのRowtestと同様の方法で使用できます。そこにクラス名が付いたテストケースソースを作成できます。次に、TestCassOurce属性が属性を飾るすべてのテストを飾ることができます。次に、Activator.createinStanceを使用して、インターフェイスにキャストできれば設定できます。
このようなもの(注 - ヘッドコンパイル)
string[] MyClassNameList = { "Class1", "Class2" };
[TestCaseSource(MyClassNameList)]
public void Test1(string className)
{
var instance = Activator.CreateInstance(Type.FromName(className)) as IMyInterface;
...
}
rowtest]属性を使用できます mbunit これをする。以下の例は、メソッドを文字列に渡す場所を示して、インスタンス化するインターフェイス実装クラスを示し、リフレクションを介してこのクラスを作成します。
[RowTest]
[Row("Class1")]
[Row("Class2")]
[Row("Class3")]
public void TestMethod(string type)
{
IMyInterface foo = Activator.CreateInstance(Type.GetType(type)) as IMyInterface;
//Do tests on foo:
}
行]属性では、テストの入力値やメソッドの呼び出しによって返される予想値など、任意の数の入力パラメーターを渡すことができます。テスト方法入力引数として、対応するタイプの引数を追加する必要があります。
これは私の具体的な実装です Avandeursenの答え:
[TestClass]
public abstract class IMyInterfaceTests
{
protected abstract IMyInterface CreateInstance();
[TestMethod]
public void SomeTest()
{
IMyInterface instance = CreateInstance();
// Run the test
}
}
次に、各インターフェイスの実装で次のテストクラスを定義します。
[TestClass]
public class MyImplementationTests : IMyInterfaceTests
{
protected override IMyInterface CreateInstance()
{
return new MyImplementation();
}
}
SomeTest
コンクリートごとに1回実行されます TestClass
に由来する IMyInterfaceTests
. 。抽象的なベースクラスを使用することにより、模擬実装の必要性を避けます。必ず追加してください TestClassAttribute
両方のクラスまたはこれは機能しません。最後に、必要に応じて、実装固有のテスト(コンストラクターなど)を子クラスに追加できます。