S2JUnit4でSAStrutsのActionをテストするには、あれこれとdiconファイルやらを調整する必要があった。

S2JUnit4でSAStrutsのActionをテストしてみたら

S2JUnit4の導入メモ | roundropブログ implements Programmable
で、S2JUnit4の導入について書きましたが、SAStrutsのActionをテストしてみたら全然動かなかった。
いろいろとdiconファイルやらを調整する必要があった。

ActionCustomizerでNullPointerExceptionが発生する

まずは、ActionCustomizerでNullPointerExceptionが発生。

java.lang.NullPointerException
at org.seasar.struts.customizer.ActionCustomizer.customize(ActionCustomizer.java:81)
at org.seasar.framework.container.customizer.CustomizerChain.doCustomize(CustomizerChain.java:140)
at org.seasar.framework.container.customizer.AbstractCustomizer.customize(AbstractCustomizer.java:145)
:

これは、テスト実行に不要な部分を削ったテスト用のcustomizer.diconをつくって解決した。

env_ut.txtを追加、中身を“ut“にする。
で、customizer_ut.diconを新規作成。
内容は以下のような感じに、AOP部分をがっつり削ったものを用意。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<components>
  <include path="default-customizer.dicon"/>
  <component name="actionCustomizer"
    class="org.seasar.framework.container.customizer.CustomizerChain">
  </component>
  <component name="formCustomizer"
    class="org.seasar.framework.container.customizer.CustomizerChain">
  </component>
  <component name="serviceCustomizer"
    class="org.seasar.framework.container.customizer.CustomizerChain">
  </component>
</components>

ActionのフィールドのServiceなどのDIに失敗する

app.diconを読み込ませることで解決。
s2junit4.diconに以下を追加。

<component class="org.seasar.framework.unit.impl.ConfigFileIncluderImpl">
  :
  <initMethod name="addConfigFile">
    <arg>"test-app.dicon"</arg>
  </initMethod>
:
</component>

一応、テスト用ということでtest-app.diconという名前にしておいた。

テストクラスにDIしたフィールドに対する操作は@Beforeじゃなくて@PostBindFieldsで

S2TestCaseのsetUpAfterBindFields()相当が@PostBindFileds。

:
private Map<String, Object> sessionScope;
@Before
public void before() {
    //ここではsessionScopeはまだDIされていないので、さわるとヌルポになる
}
@PostBindFields
public void postBindFields() {
    //@PostBindFieldsであればok
    User user = new User();
    user.name = "hoge";
    sessionScope.put("user", user);
}

Ajaxリクエストのテスト

Ajaxリクエストの場合は、SAStrutsでは、ResponseUtil#write()しつつ、return nullする感じになるので、ResponseUtil#write()した内容をassertすることになる。
が、これが取り出せない。。
ResponseUtilからはResponseはMockHttpServletResponseで取り出せ、getOutputStream()でMockServletOutputStreamImplが取り出せるのだが、内容が取り出せない。
しかたがないのでリフレクションで解決。。。ソース読んでも無理っぽかったが、何かやり方があるのだろうか?

MockHttpServletResponse mockResponse = (MockHttpServletResponse) ResponseUtil.getResponse();
MockServletOutputStreamImpl mockOutputStream = (MockServletOutputStreamImpl) mockResponse.getOutputStream();
String json = MockServletOutputStreamUtil.getStringFromMockServletOutputStream(mockOutputStream);
assertThat(json, is(expect));

リフレクションで無理矢理取り出すUtil。
public class MockServletOutputStreamUtil {
  public static String getStringFromMockServletOutputStream( MockServletOutputStreamImpl mockServletOutputStream)
  throws IllegalArgumentException, IllegalAccessException, UnsupportedEncodingException {
    Field field
    = ReflectionUtil.getDeclaredField(MockServletOutputStreamImpl.class, "outputStream");
    field.setAccessible(true);
    ByteArrayOutputStream baos
     = (ByteArrayOutputStream) field.get(mockServletOutputStream);
    return new String(baos.toByteArray(), "UTF-8");
  }
}