このエントリは Java Advent Calendar -ja 2010 : ATND の 5日目のものです。
やぁ、みなさんStruts使ってますか!最近「いつまでStruts1を使い続けるの? - 達人プログラマーを目指して」とか「Strutsの終焉: プログラマの思索」とかで、何かと話題のStruts1ですが、もろもろの事情で使わなければいけないことって多いですよね?ね!
で、仕方なく使わざるを得ないStrutsですが、ActionのexecuteメソッドがそのままだとJUnitなんかでUnitTest(できない|できても大変)で困ります。
そんな時は、Mockを使ってテストしましょう!今回はMockitoを使います。
こんなActionがあったとして。
package com.example.masaru.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class TestAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return mapping.findForward("success");
}
}
Mockitoを使って、こんなテストコードを書きます。
package com.example.masaru.action;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.junit.Test;
public class TestActionTest {
@Test
public void testExecute() throws Exception {
TestAction action = new TestAction();
// Action.executeの引数をMockにする
ActionMapping mapping = mock(ActionMapping.class);
ActionForm form = mock(ActionForm.class);
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
// mappingの挙動を擬装
when(mapping.findForward("success")).thenReturn(
new ActionForward("success", "/dest", false));
// action.execute呼び出し
ActionForward forward = action.execute(mapping, form, request, response);
// mapping.findForwardが呼ばれたか検証
verify(mapping).findForward("success");
// 戻り値を検証
assertThat(forward, is(notNullValue()));
assertThat(forward.getName(), is("success"));
assertThat(forward.getPath(), is("/dest"));
}
}
こんな風にSessionをActionで使う場合は・・・
package com.example.masaru.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class TestAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
HttpSession session = request.getSession();
String hoge = (String)session.getAttribute("session_key");
return mapping.findForward("success");
}
}
テスト側でrequestのgetSessionメソッドを擬装します。
package com.example.masaru.action;
import static org.mockito.Mockito.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.junit.Test;
public class TestActionTest {
@Test
public void testExecute() throws Exception {
TestAction action = new TestAction();
// Action.executeの引数をMockにする
ActionMapping mapping = mock(ActionMapping.class);
ActionForm form = mock(ActionForm.class);
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
// request、sessionの挙動を擬装
HttpSession session = mock(HttpSession.class);
when(session.getAttribute("session_key")).thenReturn("foo");
when(request.getSession()).thenReturn(session);
// action.execute呼び出し
action.execute(mapping, form, request, response);
// session関連処理が呼ばれたか検証
verify(request).getSession();
verify(session).getAttribute("session_key");
}
}
他にも工夫次第で、いくらでも柔軟に対応できますよ♪
というわけで、皆さんもMockを使って、嫌われ者のStruts1でも快適TDDライフを謳歌してみてはいかがでしょうか?
ちなみに、当たり前ですがstruts-config.xmlやらvalidation.xmlやらの設定は読み込まれませんので、その辺はご注意くださいませ<(_ _)>