web-dev-qa-db-ja.com

JunitとEasyMockを使用して、自動配線表記でクラスを単体テストしますか?

@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(){
    //??????
  } 

}

正しい方向にプッシュするのは素晴らしいことです。

ありがとう

27
sc_ray

ReflectionTestUtils を使用して、依存関係をフィールドに直接反射的に挿入できます。例:.

ReflectionTestUtils.setField( testInstance, "fieldName", fieldValue );

とにかく、テストでのみ使用される、パッケージに表示されるセッターメソッドをクラスに追加することが望ましいと主張する人もいます。または、自動配線フィールドではなく自動配線コンストラクターを使用して、テストの依存関係をそこに挿入します。

34
skaffman

リフレクションを介してこれらのフィールドを設定することは可能ですが、そうすると、開発ツールがこれらのフィールドの使用法を見つけることができなくなり、将来的にSomeClassToTestをリファクタリングすることが難しくなります。

これらのフィールドにパブリックセッターを追加し、代わりに@Autowiredアノテーションを配置することをお勧めします。これにより、リフレクションが回避されるだけでなく、クラスの外部インターフェイスが明確になり、単体テストでこのインターフェイスのみが使用されるようになります。 SomeClassToTestはすでにSomeOtherClassインターフェースを実装していることがわかります。また、SomeClassToTestのクライアントはこのインターフェースのみを使用していると思います。したがって、SomeClassToTestpublic。

さらに良いことに、コンストラクタインジェクションを使用して、フィールドを最終にします。コンストラクターの引数には引き続き@Autowiredを使用できます。

6
Kkkev

受け入れられた回答、つまり自分でリフレクションを使用する(モックフレームワークなし)回答はお勧めしません。

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");
  }
}
2
krm