web-dev-qa-db-ja.com

Guice注射をテストするにはどうすればよいですか?

私はオブジェクトを配線する責任をGoogle Guiceに与えました。しかし、バインディングが正常に機能しているかどうかをどのようにテストできますか?

たとえば、依存関係Aを持つクラスBがあるとします。 Bが正しく注入されていることをどのようにテストできますか?

_class A {
    private B b;
    public A() {}

    @Inject
    public void setB(B b) {
        this.b = b
    }
}
_

AにはgetB()メソッドがないため、_A.b_がnullではないことを表明したいことに注意してください。

31
yeraycaballero

複雑なGuiceプロジェクトの場合は、テストを追加して、モジュールを使用してクラスを作成できることを確認する必要があります。あなたの例では、BがGuiceが作成方法を理解できなかったタイプである場合、GuiceはAを作成できません。Aがサーバーを起動する必要はなく、サーバーが要求、それは問題を引き起こすでしょう。

私のプロジェクトでは、重要なモジュールのテストを作成しています。モジュールごとに、 requireBinding() を使用して、モジュールが必要とするが定義しないバインディングを宣言します。テストでは、テスト中のモジュールと必要なバインディングを提供する別のモジュールを使用して、Guiceインジェクターを作成します。 JUnit4とJMockを使用した例を次に示します。

_/** Module that provides LoginService */
public class LoginServiceModule extends AbstractModule {
  @Override 
  protected void configure() {
    requireBinding(UserDao.class);
  }

  @Provides
  LoginService provideLoginService(UserDao dao) {
    ...
  }
}

@RunWith(JMock.class)
public class LoginServiceModuleTest {
  private final Mockery context = new Mockery();

  @Test
  public void testModule() {
    Injector injector = Guice.createInjector(
        new LoginServiceModule(), new ModuleDeps());

    // next line will throw an exception if dependencies missing
    injector.getProvider(LoginService.class);
  }

  private class ModuleDeps extends AbstractModule {
    private final UserDao fakeUserDao;

    public ModuleDeps() {
      fakeUserDao = context.mock(UserDao.class);
    }

    @Override 
    protected void configure() {}

    @Provides
    Server provideUserDao() {
      return fakeUserDao;
    }
  }
}
_

テストがプロバイダーのみを要求することに注意してください。これで、Guiceがバインディングを解決できると判断できました。 LoginServiceがプロバイダーメソッドによって作成された場合、このテストはプロバイダーメソッドのコードをテストしません。

このテストは、正しいものをUserDaoにバインドしたかどうか、またはUserDaoが正しくスコープ指定されたかどうかもテストしません。これらの種類のことはめったにチェックする価値がないと主張する人もいます。問題がある場合は、一度だけ発生します。 「恐怖が退屈になるまでテストしてください」。

新しいインジェクションポイントを追加することが多く、バインディングの追加を忘れることが多いので、モジュールテストは便利です。

requireBinding()呼び出しは、Guiceがインジェクターを返す前に欠落しているバインディングをキャッチするのに役立ちます!上記の例では、requireBinding()呼び出しが存在しない場合でもテストは機能しますが、ドキュメントとして機能するため、これらの呼び出しが好きです。

より複雑なモジュール(ルートモジュールなど)の場合、 Modules.override() を使用して、テスト時に不要なバインディングをオーバーライドできます(たとえば、ルートオブジェクトを確認したい場合)作成するために、おそらくデータベースに接続するオブジェクトを作成したくありません)。単純なプロジェクトの場合、最上位モジュールのみをテストできます。

Guice nullを挿入しません は、フィールドが_@Nullable_で注釈されている場合を除き、注入されたオブジェクトがnullでないことをテストで確認する必要がほとんどないことに注意してください。実際、コンストラクタに_@Inject_で注釈を付けるとき、パラメータがnullであるかどうかを確認する必要はありません(実際、テストでは、コンストラクタにnullを注入してテストを維持していますシンプル)。

42
NamshubWriter

構成をテストするもう1つの方法は、アプリをエンドツーエンドでテストするテストスイートを用意することです。エンドツーエンドテストは、名目上はユースケースをテストしますが、アプリが正しく構成されていることを間接的にチェックします(すべての依存関係が配線されているなど)。一方、単体テストは、コードがデプロイされているコンテキストではなく、ドメインのみに焦点を当てる必要があります。

NamshubWriterの回答にも同意します。ユニットテストとは別のテストスイートにグループ化されている限り、構成をチェックするテストに反対しているわけではありません。

4
murungu

私見、あなたはそれをテストすべきではありません。 Google Guiceの連中は、注入が期待どおりに機能することを断言する単体テストを用意しています。結局のところ、それがGuiceの目的です。独自のコード(AおよびB)のテストのみを作成する必要があります。

2
gpampara