JUnit Test with JDO

オブジェクトの永続化の際にキーの自動生成あたりで躓いてしまい、Unit Testを書くことに。
普通に書いて動かしてみたら、

java.lang.NullPointerException: No API environment is registered for this thread.
	at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:74)
	at com.google.appengine.api.datastore.DatastoreServiceImpl.beginTransaction(DatastoreServiceImpl.java:295)
	at org.datanucleus.store.appengine.RuntimeExceptionWrappingDatastoreService.beginTransaction(RuntimeExceptionWrappingDatastoreService.java:209)
	at org.datanucleus.store.appengine.jdo.DatastoreJDOTransaction.begin(DatastoreJDOTransaction.java:50)
...

と怒られてしまいました。何かスレッドコンテキストが必要らしい。確かにJDO等の初期化処理をしていないので、動かないと言われても仕方がないのかな。
ここにあるように、appengine-api-stubs.jarとappengine-local-runtime.jarをbuild pathに追加して、TestCase#setUp()で以下のコードを書いてみたものの、

	@Before
	public void setUp(){
		ApiProxy.setEnvironmentForCurrentThread(new LifecycleEnvironment());
        	ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(".")){});
	}
The type com.google.appengine.tools.development.ApiProxyLocalImpl is not visible

と怒られてしまいました。
そもそも先ほどの2つのjarファイルはeclipseのpluginsフォルダ下にあり、そこにbuild pathを通しているのですが、これが正しい方法なのか大分疑わしい…。SDKのバージョン変わったらこっちも修正するのだろうか。ApiProxyLocalImplというクラス名からして、大分アドホックな感じがしますが…。

それはそれとして、このApiProxyLocalImplというクラスは「appengine-local-runtime.jar」に含まれているようですが、スコープはパッケージローカルになっているようです。

// Compiled from ApiProxyLocalImpl.java (version 1.5 : 49.0, super bit)
class com.google.appengine.tools.development.ApiProxyLocalImpl implements com.google.appengine.tools.development.ApiProxyLocal {

コンソールを見ると、何やらエラーが。

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.google.appengine.tools.util.Logging.initializeLogging(Logging.java:36)
	at com.google.appengine.tools.enhancer.Enhance.main(Enhance.java:40)
Caused by: java.lang.IllegalArgumentException: Unable to find C:\eclipse\eclipse3.4SR2\plugins\com.google.appengine.eclipse.sdkbundle.1.3.3_1.3.3.v201004232023\appengine-java-sdk-1.3.3.1\lib\impl
	at com.google.appengine.tools.info.SdkInfo._getLibs(SdkInfo.java:67)
	at com.google.appengine.tools.info.SdkInfo.getLibs(SdkInfo.java:56)
	at com.google.appengine.tools.info.SdkImplInfo.<clinit>(SdkImplInfo.java:24)
	... 2 more

これはどうもウッカリpluginsフォルダ下のappengineのSDKのフォルダ構成を変えてしまった為だったようです。適当に直したら消えました。

英語の方のページを見たところ、ApiProxyLocalImplではなくLocalServiceTestHelperというクラスが使われていたので、こっちを試してみることに。appengine-testing.jarとappengine-api-stubs.jarをbuild pathに追加して、

    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    @Before
    public void setUp() {
        helper.setUp();
    }

    @After
    public void tearDown() {
        helper.tearDown();
    }
    
	@Test
	@Transaction
	public void testRegisterDailyLogAndTimeLog(){
        ....

上記のように記述し、「Run JUnit Test」を実行したところ、JDOまわりも動作することを確認しました。SDKのバージョンは1.3.3.1です。

無事JUnit Testが動作したのでキーの生成の部分を確認したところ、子エンティティを作成した際に、親→子への参照を設定していなかった為、子のPKが自動で設定されなかったようです。親←子への参照は設定していたのですが、それだけだと子のキーの生成は行われませんでした。親→子の設定を行い、キーが生成されることを確認しました。