Hatena::ブログ(Diary)

やさしいデスマーチ このページをアンテナに追加 RSSフィード

札幌のWebエンジニアの綴る日常と開発の日々。
GoogleAppEngine/slim3/Django/NetBeans/Swing/JavaFXを中心にお届け。

2011-03-24

Scenic3のAppUrlsに関するテスト

| 11:58 |  Scenic3のAppUrlsに関するテストを含むブックマーク

sue445さんのエントリーにもあるように、Scenic3の弱点の1つにAppUrlsに各ページクラスを個別に登録しなくてはならないという事があります。これは、ページクラスからAPTを使ってControllerクラス群を生成し、さらにそれらのControllerをディスパッチするMatcherを生成する仕組みでScenic3が設計されている事に起因します。APTの制約として、1つのクラスから抽出できるアノテーションから複数のクラスは生成できるのですが、幾つかのクラスに分散したアノテーションをまとめる事はできないのです*1。したがって、次のような欠点があるのです。

Controllerクラスが増えすぎずStrutsライクにコードを書けるため結構使いやすいのですが、Pageクラスを追加する度にAppUrlsにも対応するMatcherクラスを追加しないといけないのが難点です。

解決方法の1つとしては、AppUrlsを動的に生成するという事が考えられます。つまり、クラスをクロールするわけです。しかし、この解決方法ではSpin-upに影響が大きいという問題があるため、GAEでは採用できません*2

でも、自分で使っていても、Matcherを追加し忘れるんです・・・。

これについては何か解決策ないかなーとは思いつつ、ユニットテストをすれば気付くからいいや*3と思う所もあり、優先度は低く考えていました。ですが、ユニットテストを書いて走らせてみると「あれ?なんで通らないんだろ・・・」という事があるわけです。これはちょっと良くないです。

というわけで、sue445さんのエントリーにヒントを得て、MatcherにPageクラスが登録されているかを検証する事に対応しました。ただし、バージョン0.5.0(3月末までにリリース予定)からです。使い方としては、こんな感じ。

public class SimplePageTest extends PageTestCase {

    public SimplePageTest() {
        super(AppUrls.class, SimplePage.class);
    }
   // test
}

これまでもPageTestCaseというのはありましたが、コンストラクタを改良し、どのAppUrlsを使い、どのPageクラスのテストであるかを引数で渡すようにしています。コンストラクタでは、AppUrlsにPageクラスが登録されているかを検証し、登録されていない場合は、コンストラクタの時点でテストが失敗するようにしました。

junit.framework.AssertionFailedError: scenic3sample.controller.AppUrls don't contains scenic3sample.page.SimplePage

at junit.framework.Assert.fail(Assert.java:47)

at junit.framework.Assert.assertTrue(Assert.java:20)

at scenic3.tester.PageTestCase.<init>(PageTestCase.java:34)

at scenic3sample.page.SimplePageTest.<init>(SimplePageTest.java:12)

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:202)

//略

欠点としては、ユニットテストを書かないと結局は検証できないと言うことですが、ほとんどの人は書くと信じています。

尚、検証メソッド自体は、staticメソッドとしてPageTestCaseに定義されていますので、次のように直接テストしても構いません。

public class AppUrlsTest {
    @Test
    public void contains_SimplePage() throws Exception {
        PageTestCase.assertAppUrls(AppUrls.class, SimplePage.class);
    }
}

ただし、テストに追加するのを忘れるのでオススメしません。

*1:個々のクラスが独立してAPTを発火するため

*2:アイディア元のt2-frameworkではクロールするアプローチがとられている

*3:GoogleAppEngineを使う人であればユニットテストはしますよね!

sue445sue445 2011/03/24 21:52 対応乙です。
自分のコードだとゴリ押しな上にProduction環境上で動かないため、shujiさんのコードの方がスマートですね。
これでまたオレオレ実装が1つ減りましたw

akiranekoakiraneko 2011/03/25 16:57 少し古いですが、まとまっている資料として、LSI C-86試食版のマニュアルが概念を学ぶのに適していると思います。すべてを理解する必要はありませんが、一度斜め読みをしてみるぐらいがおすすめです
この本は買いましたが積み本しています。。。

トラックバック - http://d.hatena.ne.jp/shuji_w6e/20110324/1300935489