appengine java night #2b
DESCRIPTION
TRANSCRIPT
appengine java night #2自動テストの仕組みとノウハウ+α
shin1ogawa@株式会社トップゲート
自動テスト環境について
自動テスト環境AppEngine環境の仕組みローカル環境だけではなく、AppEngineの各環境はすべて
ApiProxy#getDelegate()で取得されるDelegateオブジェクト経由で実行される。デプロイ環境ではWebコンテナがDelegateオブジェクトを設定するし、ローカルでWebコンテナを起動したときも同じ。また、
ApiProxy#getCurrentEnvironment()
で取得されるEnvironmentオブジェクトから環境情報(ApplicationID, versionID等)を取得できる必要もある。
自動テスト環境手動でAppEngine環境の準備をする
JUnit等、SDKのWebコンテナを使用しない環境ではそれらのオブジェクトを生成してApiProyに設定してやる必要がある。• Environmentのは独自に実装し、ApiProxy#setEnvironmentForCurrentThread()で設定する。
• Delegateの実装としては ApiProxyLocalImpl クラスを生成してApiProxy#setDelegate()で設定する。
自動テスト環境Environment•スレッドごとに存在する• ApplicationID, versionID, 認証済みか?認証済みならそのアカウントは?管理者権限を持っているか?等を返す必要がある。
•ローカル環境のWebコンテナ上ではSingleThreadで動作するので、常にひとつだけ。
•マルチスレッドで動作させる場合は各スレッドごとに ApiProxy#setEnvironmentForCurrentThread()してやる必要がある。
自動テスト環境Delegateの実装: ApiProxyLocalImpl
• Delegateの実装というよりは、ローカル環境用のサービスのスタブ実装への接続を行うためのアダプタで、Delegateよりも随分大きい実装を含んでいる。
•コンストラクタに指定したフォルダをルートフォルダとしてサービスのスタブを初期化する。•指定したフォルダ配下にWEB-INF/queue.xmlやdatastore-indexes.xmlを用意しておくと、サービスのスタブ開始時にそれを読み込んでくれる。
自動テスト環境Delegateを実装する
•デフォルトの実装を使用しなければサービスのスタブを使用できないのでこれを継承するかこれへ処理を委譲するDelegateを自前で実装する事は可能。•継承すると…ローカル/デプロイ環境に依存してしまう。•内部でApiProxy#getDelegate()を取得し、それへ委譲する実装にする事で、各サービスへのアクセスをフックする事が可能。AOPっぽいカンジ。
自動テスト環境Delegateを実装するclass MyDelegate implements Delegate { Delegate original = ApiProxy.getDelegate(); public byte[] makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException { System.out.println(service+”:”+method); return original.makeSyncCall( environment, service, method, requst); }}
自動テスト環境makeSyncCall()をほげってみる?
byte[] Delegate#makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException
自動テスト環境makeSyncCall()をほげってみる?
byte[] Delegate#makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException
自動テスト環境makeSyncCall()をほげってみる?•例えば datastore_v3#GET の場合•送信時: DatastorePb.GetRequest• new GetRequest().mergeFrom(byte[])• GetRequest#keyIterator()で引数のKeyのIteratorを取得できる。
•受信時: DatastorePb.GetResponse• new GetResponse().mergeFrom(byte[])• GetResponse#entityIterator()で返り値のEntityのIteratorを取得できる。
自動テスト環境テスト可能な範囲を増やす•例えばMail送信のテスト
• MailServiceはローカル環境では動作しないが、Delegate#makeSyncCall()経由でサービスのStubまでは実行される。
• makeSyncCall()に渡されたbyte[]からMailServicePb.MailMessageオブジェクトを組み立て直し、MailMessage#getCC()...等でメールの内容をassertする。
自動テストではないけれども…?
デプロイ環境でも使える!サービス実行前後に処理を実行する
•例えば…• datastore_v3#GETをフックする• memcache#GETをして、存在すればdatastoreへはアクセスせずにmamcache#GETの結果を返す
• datastore_v3#PUT/DELETEをフックする• memcache#DELETEをしてからdatastoreへアクセする
ご清聴ありがとうございました!
shin1ogawa@株式会社トップゲート