私はJava SE環境で依存関係注入にWELD-SEを使用してプログラミングしています。したがって、クラスの依存関係は次のようになります。
_public class ProductionCodeClass {
@Inject
private DependencyClass dependency;
}
_
このクラスの単体テストを作成するときは、DependencyClass
のモックを作成しています。実行するすべてのテストで完全なCDI環境を開始したくないので、モックを手動で「挿入」します。
_import static TestSupport.setField;
import static org.mockito.Mockito.*;
public class ProductionCodeClassTest {
@Before
public void setUp() {
mockedDependency = mock(DependencyClass.class);
testedInstance = new ProductionCodeClass();
setField(testedInstance, "dependency", mockedDependency);
}
}
_
静的にインポートされたメソッドsetField()
テストで使用するツールを使用して、クラスに自分自身を記述しました。
_public class TestSupport {
public static void setField(
final Object instance,
final String field,
final Object value) {
try {
for (Class classIterator = instance.getClass();
classIterator != null;
classIterator = classIterator.getSuperclass()) {
try {
final Field declaredField =
classIterator.getDeclaredField(field);
declaredField.setAccessible(true);
declaredField.set(instance, value);
return;
} catch (final NoSuchFieldException nsfe) {
// ignored, we'll try the parent
}
}
throw new NoSuchFieldException(
String.format(
"Field '%s' not found in %s",
field,
instance));
} catch (final RuntimeException re) {
throw re;
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
}
}
_
このソリューションについて私が気に入らないのは、新しいプロジェクトで何度もこのヘルパーが必要になることです。私はすでにそれをテスト依存としてプロジェクトに追加できるMavenプロジェクトとしてパッケージ化しました。
しかし、他に欠けている一般的なライブラリで作成されたものはありませんか?これを行う一般的な方法についてのコメントはありますか?
Mockitoはすぐにこれをサポートします。
_public class ProductionCodeClassTest {
@Mock
private DependencyClass dependency;
@InjectMocks
private ProductionCodeClass testedInstance;
@Before
public void setUp() {
testedInstance = new ProductionCodeClass();
MockitoAnnotations.initMocks(this);
}
}
_
_@InjectMocks
_ アノテーションは、テストクラスでモックされたクラスまたはインターフェースの注入をトリガーします。この場合はDependencyClass
:
Mockitoはタイプごとに注入しようとします(タイプが同じ場合は名前を使用します)。インジェクションが失敗しても、Mockitoは何もスローしません。依存関係を手動で満たす必要があります。
ここでは、mock()
を呼び出す代わりに、_@Mock
_アノテーションも使用しています。 mock()
を使用することもできますが、アノテーションを使用することをお勧めします。
補足として、TestSupport
に実装した機能をサポートするリフレクションツールがあります。そのような例の1つは ReflectionTestUtils
です。
おそらくより良いのは コンストラクタインジェクション を使用することです:
_public class ProductionCodeClass {
private final DependencyClass dependency;
@Inject
public ProductionCodeClass(DependencyClass dependency) {
this.dependency = dependency;
}
}
_
ここでの主な利点は、クラスが依存するクラスが明確であり、すべての依存関係を提供しないと簡単に構築できないことです。また、注入されたクラスをfinalにすることもできます。
これにより、_@InjectMocks
_は不要になります。代わりに、コンストラクターのパラメーターとしてモックを提供して、クラスを作成します。
_public class ProductionCodeClassTest {
@Mock
private DependencyClass dependency;
private ProductionCodeClass testedInstance;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
testedInstance = new ProductionCodeClass(dependency);
}
}
_
Mockitosの組み込み関数では不十分な場合の代替策:試してみてください needle4j.org
これは、モックと具象インスタンスのインジェクションを可能にし、ライフサイクルシミュレーションのpostConstructもサポートするインジェクション/モックフレームワークです。
public class ProductionCodeClassTest {
@Rule
public final NeedleRule needle = new NeedleRule();
// will create productionCodeClass and inject mocks by default
@ObjectUnderTest(postConstruct=true)
private ProductionCodeClass testedInstance;
// this will automatically be a mock
@Inject
private AServiceProductionCodeClassDependsOn serviceMock;
// this will be injected into ObjectUnderTest
@InjectIntoMany
private ThisIsAnotherDependencyOfProdcutionCodeClass realObject = new ThisIsAnotherDependencyOfProdcutionCodeClass ();
@Test
public void test_stuff() {
....
}
}