3

Guice と Guice Servlet 拡張機能を使用してインスタンス化された Java Web アプリケーションがあります。このアプリケーションには、Guice によってインスタンス化される Quartz ジョブも含まれています。これらのジョブの単体テストを書きたいと思います。

ジョブ クラスは、Provider<HttpServletRequest>. get生産的なセットアップでは、ジョブは Guice によって正常にインスタンス化でき、ジョブは期待どおりに機能します。これは、サーブレット リクエスト プロバイダーでをトリガーするコラボレーターのコードを呼び出すことがないためです。getジョブは、サーブレットへの HTTP 要求の一部としてではなく、一部のワーカー スレッドによって実行されるため、このような呼び出しは失敗します。

ここで私の質問は、JUnit テストで Guice をセットアップして同じ動作を得る方法です。つまり、ジョブ クラスをインスタンス化できますが、範囲外の@RequestScopedオブジェクトを使用しようとするとすべて失敗します。


2 つの簡単な解決策がありますが、私にはうまくいきません。

何もバインドしないHttpServletRequestと、テスト セットアップでジョブをインスタンス化しようとするとエラーが発生します。

com.google.inject.CreationException: Guice creation errors:

1) No implementation for javax.servlet.http.HttpServletRequest was bound.
  while locating com.google.inject.Provider<javax.servlet.http.HttpServletRequest>

一方、モックインスタンスをバインドするだけの場合、たとえば

@Override
protected void configure() {
    bind(HttpServletRequest.class).toInstance(mock(HttpServletRequest.class));
}

その後、ジョブをインスタンス化できますが、ジョブがサーブレット要求インスタンスを使用する場合にテスト エラーが発生しなくなりました。では、Guice がプロバイダーをインスタンス化できるようにバインディングを作成するにはどうすればよいでしょうか。ただし、プロバイダーの使用は失敗しますか?

4

1 に答える 1

3

@RequestScoped何度か試行した後、テスト モジュールでオブジェクトをバインドする方法を見つけました。

@Override
protected void configure() {
    bindScope(RequestScoped.class, ServletScopes.REQUEST);

    bind(ServletRequest.class).toProvider(unusableProvider(ServletRequest.class)).in(RequestScoped.class);
    bind(HttpServletRequest.class).toProvider(unusableProvider(HttpServletRequest.class)).in(RequestScoped.class);
    bind(ServletResponse.class).toProvider(unusableProvider(ServletResponse.class)).in(RequestScoped.class);
    bind(HttpServletResponse.class).toProvider(unusableProvider(HttpServletResponse.class)).in(RequestScoped.class);
}

private static <T> Provider<T> unusableProvider(final Class<T> type) {
    return new Provider<T>() {
        @Override
        public T get() {
            throw new IllegalStateException("Unexpected call to provider of " + type.getSimpleName());
        }
    };
}

テストは request スコープに入ることはありません (つまり、 への呼び出しはありませんServletScope.scopeRequest)。そのため、テストでオブジェクトを取得しようとするRequestScopedと、本番環境とまったく同じエラーが発生します。

com.google.inject.ProvisionException: Guice provision errors:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

実際には「使用できないプロバイダー」をバインドする必要はありません。追加のセーフティ ネットとしてバインドしただけです。つまり、このソリューションは、明示的にバインドされていないが、アノテーションが付けられ@RequestScoped、Guice によって自動的に検出されるクラスに対しても機能するはずです。

于 2015-06-26T13:07:33.760 に答える