質問
私は同様の動作を持ついくつかのクラスを開発しましたが、それらはすべて同じインターフェイスを実装しています。適切なオブジェクトを作成し、インターフェイスを返すファクトリを実装しました。ファクトリ用の単体テストを作成しています。返されるのはオブジェクトへのインターフェイスだけです。工場が正しく機能していることをテストする最良の方法は何ですか?
Javaでの答えが知りたいのですが、言語を越えた解決策があれば知りたいです。
2番。答えでは、他の答えのように行われますか?そうであれば、他の回答も受け入れ済みとしてマークし、インターフェイスが返され、インターフェイスを実装した具象クラスのタイプがまったくわからないファクトリと、具象クラスが何であるかを知っている場合の両方に対処するために私の質問を言い換えます。使用済み。
解決
あなたのファクトリーメソッドがどのようなものであるかわからないので、私が今アドバイスできるのは次のことだけです
オブジェクトが探していた正しい具体的な実装であることを確認します。
IMyInterface fromFactory = factory.create(...); Assert.assertTrue(fromFactory instanceof MyInterfaceImpl1);
有効なインスタンス変数を使用して具象インスタンスが工場出荷時に設定されているかどうかを確認できます。
他のヒント
あなたがやろうとしているのは単体テストではありません
返されたオブジェクトが特定の具象クラスのインスタンスであるかどうかをテストする場合、それは単体テストではありません。統合テストを行っています。統合テストは重要ですが、それは同じではありません。
単体テストでは、オブジェクト自体をテストするだけで済みます。返された抽象オブジェクトの具象型をアサートすると、返されたオブジェクトの実装をテストすることになります。
オブジェクトの単体テスト全般
単体テストの際には、次の 4 つのことを主張する必要があります。
- クエリ (void 以外のメソッド) の戻り値は、期待どおりのものです。
- コマンド (void メソッド) の副作用により、オブジェクト自体が期待どおりに変更されます。
- 他のオブジェクトに送信されたコマンドが受信されます (これは通常、モックを使用して行われます)。
さらに、オブジェクト インスタンスから観察できるものだけをテストしたいとします。パブリックインターフェース。そうしないと、実装の詳細の特定のセットに自分自身を結び付けることになります。この場合、詳細が変更された場合にはテストを変更する必要があります。
単体テスト工場
Factory での単体テストは本当に面白くありません。 クエリで返されたオブジェクトの動作には興味がありません。. 。その動作は (できれば) 他の場所でテストされ、そのオブジェクト自体の単体テスト中にテストされると考えられます。本当に関心があるのは、返されたオブジェクトに正しい値が含まれているかどうかだけです。 タイプ, 、プログラムがコンパイルできれば保証されます。
ファクトリは時間の経過とともに変化しないため (その場合、別のパターンである「ビルダー」になるため)、テストするコマンドはありません。
ファクトリはオブジェクトのインスタンス化を担当するため、これを行うために他のファクトリに依存すべきではありません。彼らは かもしれない Builder に依存しますが、それでも、Builder の正しさをテストするのではなく、Builder がメッセージを受信するかどうかだけをテストすることになっています。
これは、ファクトリでテストする必要があるのは、ファクトリが依存するオブジェクトにメッセージを送信するかどうかだけであることを意味します。依存関係の注入を使用する場合、これはほとんど簡単です。単体テストで依存関係を模擬し、メッセージが受信されることを確認するだけです。
単体テストファクトリーの概要
- 返されたオブジェクトの動作や実装の詳細をテストしないでください。ファクトリはオブジェクト インスタンスの実装に責任を負いません。
- 依存関係に送信されたコマンドが受信されるかどうかをテストします。
それでおしまい。依存関係がない場合、テストするものは何もありません。おそらく、返されたオブジェクトが null
参照。
統合テスト工場
返される抽象オブジェクト型が特定の具象型のインスタンスであるという要件がある場合、これは統合テストに該当します。
ここの他の人は、を使用してこれを行う方法にすでに答えています instanceof
オペレーター。
@cem-catikkas getClass().getName() の値を比較する方が正しいと思います。MyInterfaceImpl1 クラスがサブクラス化されている場合、サブクラスはインスタンスの MyInterfaceImpl1 であるため、テストが壊れる可能性があります。私なら次のように書き換えます。
IMyInterface fromFactory = factory.create(...);
Assert.assertEquals(fromFactory.getClass().getName(), MyInterfaceImpl1.class.getName());
これが何らかの形で失敗する可能性があると思われる場合 (想像できませんが)、2 つの検証を行ってください。
if (myNewObject instanceof CorrectClass)
{
/* pass test */
}
アップデート:
なぜこれがマークダウンされたのかわからないので、少し拡張します...
public void doTest()
{
MyInterface inst = MyFactory.createAppropriateObject();
if (! inst instanceof ExpectedConcreteClass)
{
/* FAIL */
}
}
Factory が具体的なインスタンスを返す場合は、 @パラメーター より柔軟な自動単体テストを取得するためにアノテーションを追加します。
package it.sorintlab.pxrm.proposition.model.factory.task;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import static org.junit.Assert.*;
@RunWith(Parameterized.class)
public class TaskFactoryTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ "sas:wp|repe" , WorkPackageAvailabilityFactory.class},
{ "sas:wp|people", WorkPackagePeopleFactory.class},
{ "edu:wp|course", WorkPackageCourseFactory.class},
{ "edu:wp|module", WorkPackageModuleFactory.class},
{ "else", AttachmentTaskDetailFactory.class}
});
}
private String fInput;
private Class<? extends TaskFactory> fExpected;
public TaskFactoryTest(String input, Class<? extends TaskFactory> expected) {
this.fInput = input;
this.fExpected = expected;
}
@Test
public void getFactory() {
assertEquals(fExpected, TaskFactory.getFactory(fInput).getClass());
}
}
この例は次を使用して作成されています Junit4. 。たった 1 行のコードで、Factory メソッドのすべての結果をテストできることがわかります。