@Autowiredとマークされたフィールドのいくつかを持つクラスのユニットテストを作成しようとしています。 Springがこれらのフィールドの具体的な実装を自動的に解決しているという事実を考えると、テスト実行中に依存関係として(EasyMockを介して作成された)モックオブジェクトをプラグインする方法を理解するのに苦労しています。クラスで@Autowiredを使用すると、そのクラスにセッターがないことを意味します。クラスに追加のセッターを作成せずにモックオブジェクトをプラグインする方法はありますか?
これが私が達成しようとしていることの例です:
public class SomeClassUnderTest implements SomeOtherClass{
@Autowired
private SomeType someType;
@Autowired
private SomeOtherType someOtherType;
@Override
public SomeReturnType someMethodIWouldLikeToTest(){
//Uses someType and someOtherType and returns SomeReturnType
}
}
壁にぶつかる前にテストクラスを作成する方法は次のとおりです。
public class MyTestClassForSomeClassUnderTest{
private SomeType someType;
private SomeOtherType someOtherType;
@Before
public void testSetUp(){
SomeClassUnderTest someClassToTest = new SomeClassUnderTest();
someType = EasyMock.createMock(SomeType.class);
someOtherType = EasyMock.createMock(SomeOtherType.class);
//How to set dependencies????
}
@Test
public void TestSomeMethodIWouldLikeToTest(){
//??????
}
}
正しい方向にプッシュするのは素晴らしいことです。
ありがとう
ReflectionTestUtils
を使用して、依存関係をフィールドに直接反射的に挿入できます。例:.
ReflectionTestUtils.setField( testInstance, "fieldName", fieldValue );
とにかく、テストでのみ使用される、パッケージに表示されるセッターメソッドをクラスに追加することが望ましいと主張する人もいます。または、自動配線フィールドではなく自動配線コンストラクターを使用して、テストの依存関係をそこに挿入します。
リフレクションを介してこれらのフィールドを設定することは可能ですが、そうすると、開発ツールがこれらのフィールドの使用法を見つけることができなくなり、将来的にSomeClassToTest
をリファクタリングすることが難しくなります。
これらのフィールドにパブリックセッターを追加し、代わりに@Autowired
アノテーションを配置することをお勧めします。これにより、リフレクションが回避されるだけでなく、クラスの外部インターフェイスが明確になり、単体テストでこのインターフェイスのみが使用されるようになります。 SomeClassToTest
はすでにSomeOtherClass
インターフェースを実装していることがわかります。また、SomeClassToTest
のクライアントはこのインターフェースのみを使用していると思います。したがって、SomeClassToTest
public。
さらに良いことに、コンストラクタインジェクションを使用して、フィールドを最終にします。コンストラクターの引数には引き続き@Autowired
を使用できます。
受け入れられた回答、つまり自分でリフレクションを使用する(モックフレームワークなし)回答はお勧めしません。
EasyMockのバージョン3.2以降、アノテーションを使用してモックを定義し、テスト対象のクラスに挿入できます。それを行う方法の完全な説明は、EasyMockの公式ドキュメントにあります: http://easymock.org/user-guide.html#mocking-annotations
上記のサイトの例を次に示します。
import static org.easymock.EasyMock.*;
import org.easymock.EasyMockRunner;
import org.easymock.TestSubject;
import org.easymock.Mock;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(EasyMockRunner.class)
public class ExampleTest {
@TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
@Mock
private Collaborator mock; // 1
@Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}