5

次の呼び出しを行うJUnit(4.10)単体テストを作成しましたcom.google.appengine.api.ThreadManager

ThreadManager.currentRequestThreadFactory();

このテストを実行すると、このメソッドNullPointerException内からスローされます。currentRequestThreadFactory

Caused by: java.lang.NullPointerException
    at com.google.appengine.api.ThreadManager.currentRequestThreadFactory(ThreadManager.java:39)
    at com.myapp.server.plumbing.di.BaseModule.providesThreadFactory(BaseModule.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

のソースをプルダウンして、ThreadManager39行目(NPEのソース)を見ると、次のように表示されます。

public static ThreadFactory currentRequestThreadFactory() {
        return (ThreadFactory) ApiProxy.getCurrentEnvironment().getAttributes()
            .get(REQUEST_THREAD_FACTORY_ATTR);
}

したがって、ApiProxy.getCurrentEnvironment()はnullのようであり、getAttribute()そのメソッドが呼び出されると、NPEがスローされます。これを確認するために、ユニットテストコードの上位にいくつかの新しいprintステートメントを追加しました。

if(ApiProxy.getCurrentEnvironment() == null)
    System.out.println("Environment is null.");

GAEがすべてのサービスの「テストバージョン」を提供していることを漠然と認識していますが、それらの使用方法と設定方法を(具体的に)見つけることができていません。だから私は尋ねます:GAEはそのようなテストバージョンを提供していますか?もしそうなら、どうすればApiProxyここにテストバージョンを追加できますか?そうでない場合、私のオプションは何ですか?どちらの方法(または)も静的であるため、どちらの方法(ThreadManager#currentRequestThreadFactoryまたは)もモックできないと思います。ApiProxy#getCurrentEnvironment前もって感謝します。

編集appengine-testing.jarSDKに同梱されているものがあるようです。このJARの中には、JUnitテスト中に使用できるバージョンであり、NPEをスローしなくても機能するApiProxyLocal.classと私は信じています。ApiProxyそれが事実である場合(私は確信が持てませんが)、問題は次のとおりです:ThreadManagerこのテストのためにそれを自分に注入するにはどうすればよいですか?

4

4 に答える 4

1

ThreadManager.currentRequestThreadFactory()コードから直接呼び出すことは避けることをお勧めします。代わりに、ThreadFactoryスレッドを作成する必要があるクラスに を挿入します。

これを行う簡単な方法の 1 つは、Guice を使用することです。

public static class MyService {
  private final ThreadFactory threadFactory;

  @Inject
  MyService(ThreadFactory threadFactory) {
    this.threadFactory = threadFactory;
  }

  ...
}

のテストでは、フェイクをコンストラクターに渡すか、または注入MyServiceすることができます。ThreadFactoryMyServiceExecutors.defaultThreadFactory()

プロダクション コードでは、バインディングを作成します。

bind(ThreadFactory.class)
    .toInstance(ThreadManager.currentRequestThreadFactory());

もちろん、依存性注入に飛び込む準備ができていない場合は、独自のアクセサーを作成して、ThreadFactory

于 2013-02-05T04:43:52.560 に答える
0

最後の回答に追加するには、単体テスト ケース内でスレッドを開始する場合、その Java スレッドにも ApiProxy 環境セットが必要です。

クラス LocalServiceTestCase で TestCase を拡張すると、setup メソッドは次のようになります。

super.setUp();

helper1.setUp();

setEnvironment();

どこ:

public static void setEnvironment() {

    if (ApiProxy.getCurrentEnvironment() == null) {  

        ApiProxyLocal apl = LocalServiceTestHelper.getApiProxyLocal();

        ApiProxy.setEnvironmentForCurrentThread(new TEnvironment());

        ApiProxy.setDelegate(apl);

    }
}

TEnvironment は上記の URL に記載されています。

静的な unsetEnvironment() も作成したい場合があります。

単体テストのケースで、新しい Java スレッドを開始した場合は、実行メソッドの先頭で静的メソッドを使用できます。

public void run() {

    LocalServiceTestCase.setEnvironment();
于 2013-08-28T20:34:19.937 に答える