Cactus在Model 1的web程式上確實可幫助programmer順利且簡單的完成單元測試,在struts所寫的Model 2上則
需要Mock Object的幫忙,SourceForge提供了很好用的Mock Object -- StrutsTestCase
來完成struts的單元測試,StrutsTestCase的官方網站在http://strutstestcase.sourceforge.net/
,因為底下將使用In-Container的方式測試,在了解怎麼使用StrutsTestCase,請先看一下Cactus怎麼使用。
- 範例程式
這個範例程式是個簡單的登入功能,如下圖,登入成功轉到success.jsp,失敗的話轉到fail.jsp。
- login.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<HEAD>
<%@ page
language="java" contentType="text/html;
charset=BIG5" pageEncoding="BIG5" %>
<META http-equiv="Content-Type" content="text/html; charset=BIG5">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
<html:form action="/login.do">
登入名稱: <input type="text" name="username"><br>
登入密碼: <input type="password" name="password"><br>
<input type="submit" value="登入">
</html:form>
</BODY>
</html:html>
- success.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html:html>
<HEAD>
<%@ page language="java" contentType="text/html;
charset=BIG5" pageEncoding="BIG5" %>
<META http-equiv="Content-Type" content="text/html; charset=BIG5">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
Hello, <c:out value="${username}"/>!
</BODY>
</html:html>
- fail.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html:html>
<HEAD>
<%@ page language="java" contentType="text/html;
charset=BIG5" pageEncoding="BIG5" %>
<META http-equiv="Content-Type" content="text/html; charset=BIG5">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
Fail!
</BODY>
</html:html>
- LoginAction.java
package tw.idv.idealist.cactus.actions;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import tw.idv.idealist.cactus.forms.FmLogin;
public class LoginAction extends Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
ActionErrors errors = new ActionErrors();
ActionForward forward = new ActionForward();
FmLogin fmLogin = (FmLogin) form;
if (fmLogin.getUsername().equals("steven") &&
fmLogin.getPassword().equals("1234")) {
request.setAttribute("username", fmLogin.getUsername());
forward = mapping.findForward("success");
}
else {
forward = mapping.findForward("fail");
}
return (forward);
}
}
- FmLogin.java
package tw.idv.idealist.cactus.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class FmLogin extends ActionForm {
private String username;
private String password;
public void reset(ActionMapping mapping,
HttpServletRequest request) {
}
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
return errors;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public void setPassword(String string) {
password = string;
}
public void setUsername(String string) {
username = string;
}
}
- struts-config.xml
<form-beans>
<form-bean name="fmLogin"
type="tw.idv.idealist.cactus.forms.FmLogin">
</form-bean>
</form-beans>
…
<action-mappings>
<action name="fmLogin" path="/login" scope="request"
type="tw.idv.idealist.cactus.actions.LoginAction">
<forward name="success" path="/success.jsp">
</forward>
<forward name="fail" path="/fail.jsp">
</forward>
</action>
</action-mappings>
- 測試
由官方網站上下載StrutsTestCase後解開,會發現有一個名為test.war的檔案,
將它解開,將裡面的aspectjrt-1.1.1.jar、cactus-13-1.6.1.jar、commons-beanutils.jar、commons-collections.jar、
commons-digester.jar、commons-httpclient-2.0.jar、commons-logging.jar、commons-validator.jar、crimson.jar、httpunit-1.5.4.jar、
jaxp.jar、junit-3.8.1.jar、log4j-1.2.5.jar、strutstest-2.1.3.jar放置到WEB-INF/lib,然後撰寫如下測試碼,撰寫測試碼時,要
注意以下幾點:
- 測試的TestCase要繼承MockStrutsTestCase。
- 如果要override setUP()和tearDown() method,那麼這兩個method先呼叫父類別的setUP()和tearDown() method,父類別的setUP()和
tearDown() method會做些初始化的動作。
- 使用setRequestPathInfo() method告訴struts mapping的路徑。
- 使用addRequestParameter來加入client端要傳給server的參數。
- client傳完參數後,記得呼叫actionPerform() method,這樣LoginAction就會真的被執行。
- 接著我們可以使用verifyForward()、assertEquals()、verifyActionErrors()…method檢查結果是否正確。
package tw.idv.idealist.cactus;
import java.io.File;
import servletunit.struts.MockStrutsTestCase;
public class TestLoginAction extends MockStrutsTestCase {
public void setUp() throws Exception {
super.setUp();
}
public void tearDown() throws Exception {
super.tearDown();
}
public TestLoginAction(String testName) {
super(testName);
}
public void testSuccessfulLogin() {
this.setContextDirectory(new File("e:/Tomcat4/webapps/UnitTest"));
setRequestPathInfo("/login");
addRequestParameter("username","steven");
addRequestParameter("password","1234");
actionPerform();
verifyForward("success");
assertEquals("steven", request.getAttribute("username"));
}
}
執行結果
開啟瀏覽器,連線到http://localhost/UnitTest/ServletTestRunner?suite=tw.idv.idealist.cactus.TestLoginAction&transform=yes,
可以看到如下結果。
|