【slim3】ビジネスロジックとしての”Service”
前回紹介した Model は、あくまで JavaBeans であり、それ自体に永続化の機能はありません。
BigTable への Model の永続化、および BigTable からの Model の取得といった persistence に関する処理は、Model 以外の別のクラスで定義する必要があります。
また、FrontController(後述)は画面遷移を扱うクラスであり、Struts の Action クラス同様、ビジネスロジック及び persistence の処理を定義すべきではありません。
slim3 では、ビジネスロジック及び persistence の処理を行うクラスとして、”Service”というクラスを定義・使用します。
2.Serviceの概要
Model とは異なり、Service にはアノテーションなどの slim3 特有の仕様・縛りはありません。
(後述しますが、UT には slim3 特有の仕様・縛りがあります。)
Service では、ビジネスロジック及び persistence の処理を、自由に記述することになります。
3.Datastoreによるpersistence
Model の persistence の処理は、org.slim3.datastore.Datastore クラスを利用して実装します。
Datastore クラスの API のうち、主だったものを以下に列挙します。
メソッド名 | 内容 |
---|---|
get | BigTable から Model を取得する(select) |
put | BigTable へ Model を永続化する(insert/update) |
delete | BigTable から Model を削除する(delete) |
createKey | Model の Key を生成する |
allocateId | Model の Key を生成する |
beginTransaction | トランザクションを開始する |
commit | トランザクションをコミットする |
rollback | トランザクションをロールバックする |
Datastore には大きく、
の3つの機能があります。
例1.Modelの登録
Q&A を表す Model を、BigTable へ登録する例です。
QAndA model = new QAndA(); // キー生成 model.setKey(Datastore.createKey(QAndA.class, 1L)); model.setQuestion("GAE の意味は?"); model.setAnswer("Google App Engine です。"); // Model 登録 Datastore.put(model);
4.単体テスト
Service の単体テストは、org.slim3.tester.LocalServiceTestCase クラスを継承して作成します。
このクラスは、次の2つの機能を提供してくれます。
(1)Datastore/Key を使用できる
内部で Thread/ApiProxy を操作し、Datastore/Key を使用できる環境を提供してくれます。
※前回の記事を参照。
5.単体テストの実装例
以下のメソッドを持つ、QAndAService というクラスの単体テストを行うこととします。
メソッド名 | 処理内容 |
---|---|
registerQAndA() | Q&A の Model を、BigTable へ登録する |
findQAndAById() | Key に該当する Q&A の Model を、BigTable から取得する |
package xxx.yyy.service.qanda; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slim3.datastore.Datastore; import org.slim3.datastore.EntityNotFoundRuntimeException; import org.slim3.tester.LocalServiceTestCase; import com.google.appengine.api.datastore.Key; import xxx.yyy.model.qanda.QAndA; public class QAndAServiceTest extends LocalServiceTestCase { // テスト対象クラスのインスタンス。 private QAndAService target; @Before public void before() { this.target = new QAndAService(); } @After public void after() { this.target = null; } // registerQAndA()+findQAndAById() の正常系 @Test public void registerQAndA() { QAndA model = new QAndA(); Key key = Datastore.createKey(QAndA.class, 1L); model.setKey(key); model.setQuestion("foo"); model.setAnswer("bar"); target.registerQAndA(model); // データが想定通りに登録できたことの確認 QAndA result = target.findQAndAById(1L); assertEquals( key, result.getKey()); assertEquals( "foo", result.getQuestion()); assertEquals( "bar", result.getAnswer()); } // findQAndAById() の異常系 @Test(expected=EntityNotFoundRuntimeException.class) public void findQAndAById_DataNotFoundError() { target.findQAndAById(1L); } }