読者です 読者をやめる 読者になる 読者になる

SAStruts ActionのJUnit

これはSAStruts 1.0.2の話です。1.0.3以降は知らんですよ。

SAStrutsはアクションクラスにpublicなフィールドを書くだけで依存クラスを勝手にInjectしてくれる。便利。しかし、アクセスレベルがpublicでは問題があるという話が浮上してきたので、アクションの依存クラスのフィールドをprotectedにして、@Bindingアノテ(@Resourceアノテでも良いらしい)付けることにした。

ところがアクションクラスのテストコードは今までこんな書き方をしていたので、

public class ContractActionTest extends S2TestCase {

    public HogeService hogeService;

    public void testHoge() {
        HogeAction action = new HogeAction();
        action.hogeService = this.hogeService;   // protectedフィールドへのアクセス、コンパイルエラー
		
        // 以下テストコード..
    }
}

アクションのhogeServiceプロパティをprotectedにしたためコンパイルエラー。普通はテスト対象クラスとテストクラスを同じパッケージで作るのでprotectedフィールドにもアクセスできる。しかし今回は一部のアクションで共通処理と依存クラスを親クラスにまとめており、パッケージが違うためアクセスできない。俺涙目ww、だからコード共有のための継承とかキライなんだよww

で、どうするか。そもそも、アクションクラスそのものをテストクラスに直接InjectできないのはActionCreatorが色々やってくれて問題が発生するから。だから単なるPOJOなコンポーネントとしてアクションクラスをコンテナに登録し、依存クラスの解決もコンテナにさせてしまえばいいんじゃないかと考えた。

S2Containerをコード上で弄る方法知らないけど、適当にやってみたお。

    public void testHoge() {
        S2Container container = this.getContainer();
        container.register(HogeAction.class);
        HogeAction hogeAction = (HogeAction)container.getComponent(HogeAction.class);

        assertEquals("index.jsp", hogeAction.index());  // hogeServiceを使うメソッドをコール。ぬるぽをスロー

だめだった、protectedなフィールドにはInjectしてくれない。

しかし、publicなフィールドにはInjectしてくれるようだ。ならばInterTypeを使ってセッターを作っちゃえばいいんじゃないかと考えた。たぶんComponentDefとか使えばいいんじゃないかと、適当にアタリを付けてやってみたお。

    public void testHoge() {
        ComponentDef def = new ComponentDefImpl(HogeAction.class);
        InterTypeDef type = new InterTypeDefImpl(new PropertyInterType());
        def.addInterTypeDef(type);

        S2Container container = this.getContainer();
        container.register(def);
        HogeAction hogeAction = (HogeAction)container.getComponent(HogeAction.class);

        assertEquals("index.jsp", hogeAction.index());  // hogeServiceを使うメソッドをコール。今度はOK

今度はprotectedなフィールドにもInjectされているようだ。こんな簡単に動くとは思わなかった…

ただ、こーいうテストコード増やすと後でメンテできなくなるんだよな〜