2011年5月30日月曜日

Google App Engine for Java のデータストアAPIのテストを実装してみる(その4)

サンプルコードの説明の続きです。



 putSampleData()メソッドについて説明します。


/**
  * サンプルデータをデータストアに保存するメソッド。
  */
 private void putSampleData() {
  keyList = new ArrayList<key>();
  ds = DatastoreServiceFactory.getDatastoreService();
  for (int i = 0; i < propertyNames.length; i++) {
   Entity entity = new Entity(DATA_KIND);
   entity.setProperty(propertyNames[i], propertyValues[i]);
   Key key = ds.put(entity);
   keyList.add(key);
  }
 }

putSampleData()メソッドでは、データストアにテスト用のサンプルデータを
保存しています。

ローカル変数keyListは、サンプルデータを保存するときに
データストアから取得するKeyオブジェクトを格納するjava.util.Listオブジェクトです。
次に、フィールドdsDatastoreServiceを代入します。

forで始まるループの中で、データストア(ds)にサンプルデータを保存しています。
DATA_KINDをカインド名とするEntityを生成して、
そのプロパティに
名前=propertyNames[i]
値=propertyValues[i]
をセットします。
その後、データストアにEntityを保存して、Keyを取得します。
ここで取得したKeyを、前述のkeyListに格納するわけです。





インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月29日日曜日

Google App Engine for Java のデータストアAPIのテストを実装してみる(その3)

サンプルコードの説明の続きです。


setUp()メソッドについて説明します。

/**
  * @throws java.lang.Exception
  */
 @Before
 public void setUp() throws Exception {
  helper.setUp();

  //サンプルデータをデータストアに保存する
  putSampleData();
 }


setUp()メソッドは、各テストメソッドの前に呼び出されて、
テストの前準備を行います。
そのために、
@Before
アノテーションが付いています。

メソッドの中身は、
helper.setUp();
で、LocalServiceTestHelperのセットアップを行っています。

その後、
putSampleData();
では、データストアにサンプルデータを格納しています。
putSampleData()メソッドを別に作成したのは、
後に行う説明の中で、書き換えを簡単にするためです。





インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月27日金曜日

Google App Engine for Java のデータストアAPIのテストを実装してみる(その2)

前回、Google App Engine for Javaの
データストアAPIのテストのサンプルコードを掲載しました。

今回は、サンプルコードの説明を行います。



まずは、フィールドの説明です。

private static final String DATA_KIND = "sampleDataKind";

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

 private String[] propertyNames = {"pName1","pName2","pName3","pName4","pName5"};

 private String[] propertyValues = {"pValue1","pValue2","pValue3","pValue4","pValue5"};

 private DatastoreService ds;

 private List<key> keyList;


 DATA_KIND定数は、データストアに保存するデータの、サンプル用kind名です。

 helperフィールドは、ローカル環境でGAEのサービスの機能を提供するテスト用ヘルパークラスです。このヘルパーを生成することで、サーバ上でサービスを利用するのと同じコードで、テスト用のローカル環境のサービスを呼び出すことができます。

propertyNames配列は、データストアに保存するデータのプロパティ名となる文字列の配列です。保存するサンプルデータを5つ生成するので、プロパティ名を5つそれぞれに生成しています。プロパティ名はサンプルデータごとに定義せずに、共通させて問題ありません(普通はそう)。わざわざ配列にしてあることには意味はありません。

propertyValues配列は、データストアに保存するサンプルデータの値となる文字列の配列です。

dsフィールドは、サンプルデータを保存するデータストアです。

keyListは、サンプルデータをデータストアに保存したエンティティを示すキーを要素とするjava.util.Listオブジェクトです。



インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月23日月曜日

Google App Engine for Java のデータストアAPIのテストを実装してみる

前回前々回
データストアAPIのテストを実装する上での
気が付いた事について書きました。

今回からは、テストクラスを実装して、
具体的にどういうことなのか?
ということを述べようと思います。

まずは、サンプルコードです。
import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;

/**
 * Google App Engine for Javaにおけるユニットテストのサンプルコード。
 */
public class LocalUnitTestSample {

 private static final String DATA_KIND = "sampleDataKind";

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

 private String[] propertyNames = {"pName1","pName2","pName3","pName4","pName5"};

 private String[] propertyValues = {"pValue1","pValue2","pValue3","pValue4","pValue5"};

 private DatastoreService ds;

 private List<key> keyList;

 /**
  * @throws java.lang.Exception
  */
 @Before
 public void setUp() throws Exception {
  helper.setUp();

  //サンプルデータをデータストアに保存する
  putSampleData();
 }

 /**
  * サンプルデータをデータストアに保存するメソッド。
  */
 private void putSampleData() {
  keyList = new ArrayList<key>();
  ds = DatastoreServiceFactory.getDatastoreService();
  for (int i = 0; i < propertyNames.length; i++) {
   Entity entity = new Entity(DATA_KIND);
   entity.setProperty(propertyNames[i], propertyValues[i]);
   Key key = ds.put(entity);
   keyList.add(key);
  }
 }

 /**
  * @throws java.lang.Exception
  */
 @After
 public void tearDown() throws Exception {
  //サンプルデータをデータストアから削除する
  deleteSampleData();

  helper.tearDown();
 }

 /**
  * サンプルデータをデータストアから削除するメソッド。
  */
 private void deleteSampleData() {
  Iterator<key> iter = keyList.iterator();
  while (iter.hasNext()){
   ds.delete(iter.next());
  }
 }

 @Test
 public void doTest(){
  //サンプルデータをデータストアから検索する
  for (int i = 0;i < propertyNames.length;i++){
   Query query = new Query(DATA_KIND);
   query.addFilter(propertyNames[i], FilterOperator.EQUAL, propertyValues[i]);
   PreparedQuery prepare = ds.prepare(query);
   List<entity> entitiesList = prepare.asList(FetchOptions.Builder.withDefaults());
   assertEquals(1,entitiesList.size());
   Iterator<entity> iter = entitiesList.iterator();
   while (iter.hasNext()){
    Entity entity = iter.next();
    assertTrue(propertyValues[i].equals(entity.getProperty(propertyNames[i])));
   }
  }
 }

}

このコードは動作確認済みです。
次回から、このコードの内容の説明と、
前回までの内容を示すコードの変更を行います。


インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月21日土曜日

データストアAPIのテストについての補足

前回、Google App Engine for JavaのデータストアAPIを利用した
ユニットテストの方法について書きました。

その補足です。
@Afterアノテーションを付けた、テスト終了処理の実装についてですが、
LocalServiceTestHelper.tearDown()メソッドの呼び出しを
データストアを利用するメソッド呼び出しの前に行った場合には、
そのメソッド呼び出しが正しく行われません。

データストアに関連したオブジェクトも無効になります。
例を挙げると、エンティティを保存した時に取得したキーオブジェクトは
nullとなってしまいます。





インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月15日日曜日

Google App Engine for Javaの単体テスト(データストアAPI)

Google App Engine for Javaの単体テストについての
ドキュメントの翻訳を行ってきましたが、
その中で具体的にテストコードを書いてみた時に
気になったことを書いてみます。

Google App Engineのユニットテストのドキュメント(その4)
のサンプルコードは、JUnit4を利用したテストコードです。

JUnit4では、@Testアノテーションの付いたテストメソッドを
実行する前と後に、それぞれ
@Beforeと@Afterアノテーションの付いたメソッドを実行して、
テストの前処理と後処理を行います。

データストア(またはMemcache)を利用するクラスのテストを行う場合には、
前処理でテスト用サンプルデータをセットして、
後処理で削除する
という方法をとる場合がありますが、
メソッドの呼び出しの順番によっては、例外がスローされる可能性があります。

サンプルコードでは、
@Before
public void setUp(){
  helper.setUp();
}
とだけ記述されています。
データストアにデータを保存する場合、
 helper.setUp();
の後にデータストアの操作を行う必要があります。

同様に、
@After
public void tearDown(){
  helper.tearDown();
}
のような後処理のコードでは、
helper.tearDown();
の前にデータストアの操作が必要です。

helper.setUp()とhelper.tearDown()の間を一つのスコープとして考え、
その間だけデータストアに関するオブジェクトが有効になっている
ということです。




インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月10日火曜日

Google App Engine for Javaにおけるユニットテストについて(タスクキュー)

Google App Engine for Javaのユニットテスト(その5)にて、
タスクキューのテストの書き方について
翻訳しました。

この中のサンプルコードの動作環境なのですが、

GAE 1.3.x
では動作しますが、

1.4.x
ではコンパイル時に警告が出ます。

TaskOptionsクラスがdeprecated(非推奨)となっているためです。

TaskOptionsクラスの代わりとなるタスクの設定用オブジェクトについての
ドキュメントを探してみたのですが、見つかりませんでした。
どうしたらいいのでしょう・・・。





インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月7日土曜日

Google App Engine for Javaのユニットテストのドキュメント(その7)

前回に続き、Google App Engine for Javaのテストについて
翻訳します。

ちなみに、翻訳にはKaede翻訳ツールを使っています。
もともと、こういう用途に使うために作ったものですからね。

翻訳元のドキュメントは
http://code.google.com/intl/en/appengine/docs/java/tools/localunittesting.html
です。



Writing Tests With Authentication Expectations (認証を前提とするテストの記述)
ユーザーがログインしている場合にアプリケーションが別の振る舞いをする場合や、管理者のみの機能を機能を持つ場合に、ロジックが期待されている振る舞いをするかどうか調べるテストを記述することができます。ここにその方法を示します。
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalUserServiceTestConfig;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class AuthenticationTest {

    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalUserServiceTestConfig())
            .setEnvIsAdmin(true).setEnvIsLoggedIn(true);

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

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

    @Test
    public void testIsAdmin() {
        UserService userService = UserServiceFactory.getUserService();
        assertTrue(userService.isUserAdmin());
    }
}
このサンプルでは、LocalServiceTestHelperをLocalUserServiceTestConfigを使って設定して、テスト上でUserServiceを利用できるようにしていますが、LocalServiceTestHelper上で、幾つかの認証に関する環境データの設定も行っています。

2011年5月6日金曜日

Google App Engineのユニットテストのドキュメント(その4) の訂正

以前の投稿である

Google App Engineのユニットテストのドキュメント(その4)

内のサンプルコードの訂正です。

メソッドdoTest()内の2行目と5行目内、
withLimit(10) → FetchOptions.Builder.withLimit(10)

となります。
この変更が行われないと、コンパイルエラーになって
テストを実行できません。

この部分は、データストアからエンティティを取得する数の
上限を設定するコードです。



インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月5日木曜日

Google App Engineのユニットテストのドキュメント(その6)

前回に続き、Google App Engine for Javaのテストについて
翻訳します。

ちなみに、翻訳にはKaede翻訳ツールを使っています。
もともと、こういう用途に使うために作ったものですからね。

翻訳元のドキュメントは
http://code.google.com/intl/en/appengine/docs/java/tools/localunittesting.html
です。


Writing Tests for Other Services (その他のサービスのテストの記述)


テストユーティリティは、blobstoreや他のApp Engineのサービスに対しても利用可能です。テスト用のローカル実装を持つ全てのサービスのリストは、LocalServiceTestConfigのドキュメントを参照してください。



続く。

インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/

2011年5月2日月曜日

Google App Engineのユニットテストのドキュメント(その5)

前回に続き、Google App Engine for Javaのテストについて
翻訳します。

ちなみに、翻訳にはKaede翻訳ツールを使っています。
もともと、こういう用途に使うために作ったものですからね。

翻訳元のドキュメントは
http://code.google.com/intl/en/appengine/docs/java/tools/localunittesting.html
です。



Writing Task Queue Tests (タスクキューのテストの記述)
ローカル環境でのタスクキューを使用するテストはもう少し複雑で、その理由はデータストアやmemcacheと違い、タスクキューAPIはサービスの状態を調べる方法が公開されていないからです。
タスクが予期されたパラメータと共にスケジュールされているかどうか検証するためには、ローカルタスクキュー自身にアクセスする必要があります。これを行うために、com.google.appengine.api.taskqueue.dev.LocalTaskQueueが必要となります。
import com.google.appengine.api.taskqueue.dev.LocalTaskQueue;
import com.google.appengine.api.taskqueue.dev.QueueStateInfo;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class TaskQueueTest {

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

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

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


    // Run this test twice to demonstrate we're not leaking state across tests.
    // If we _are_ leaking state across tests we'll get an exception on the
    // second test because there will already be a task with the given name.
    private void doTest() throws InterruptedException {
        QueueFactory.getDefaultQueue().add(TaskOptions.Builder.taskName("task29"));
        // give the task time to execute if tasks are actually enabled (which they
        // aren't, but that's part of the test)
        Thread.sleep(1000);
        LocalTaskQueue ltq = LocalTaskQueueTestConfig.getLocalTaskQueue();
        QueueStateInfo qsi = ltq.getQueueStateInfo().get(QueueFactory.getDefaultQueue().getQueueName());
        assertEquals(1, qsi.getTaskInfo().size());
        assertEquals("task29", qsi.getTaskInfo().get(0).getTaskName());
    }

    @Test
    public void testTaskGetsScheduled1() throws InterruptedException {
        doTest();
    }

    @Test
    public void testTaskGetsScheduled2() throws InterruptedException {
        doTest();
    }
}
注意する点として、LocalTaskqueueTestConfigにローカルサービスのインスタンスを操作させる方法と、ローカルサービスがタスクが予定されたとおりにスケジュールされていることを確実に行っていることを調べる、という点が挙げられます。全てのLocalServiceTestConfigの実装は、類似したメソッドを持っています。それらは常に必要とされるわけではありませんが、その存在が役に立つときがいつか来るでしょう。



続く。

インストール不要・無料のKaede翻訳ツール
http://kaedetrans.appspot.com/