使用StrutsTestCase测试Struts的Action类
一.前言
对于OPEADP这个项目,UT阶段本来是打算使用HttpUnit来测试相关的Action类。经过调查,发现使用StrutsTestCase更适合,因为HttpUnit要求所测试的程序先运行起来,而StrutsTestCase可以脱离相应的容器而独立测试,这样更方便于UT测试。
HttpUnit原理:HttpUnit通过模拟浏览器的行为,处理页面框架(frames),cookies,页面跳转(redirects)等。通过HttpUnit提供的功能,你可以和服务器端进行信息交互,将返回的网页内容作为普通文本、XML Dom对象或者是作为链接、页面框架、图像、表单、表格等的集合进行处理,然后使用JUnit框架进行测试,还可以导向一个新的页面,然后进行新页面的处理,这个功能使你可以处理一组在一个操作链中的页面。
二.StrutsTestCase简介
StrutsTestCase是sourceforge.org的一个开源项目,是基于Junit的方便测试struts的测试框架。它提供模拟对象(Mock Object)和Cactus两种方式来“真实”的运行Struts ActionServlet,允许在不启动servlet 引擎的情况下测试你的struts代码。
通常测试服务器端代码有两种比较常用的测试方法:
1.模仿对象(mock objects)它通过假设服务器端容器来达到测试效果;
2.容器内测试(in-container testing),它则是在真实的容器内达到测试效果;
StrutsTestCase提供两种基类(分别继承标准的Junit TestCase):
MockStrutsTestCase:
通过名字可以知道他是通过第一中方法在不启动servlet的条件下来模仿一些HttpServlet实现假设容器环境的。
CactusStrutsTestCase:
它是体现在容器内测试(真实环境测试)的,其通过另外一种测试框架(Cactus testing framework:http://jakarta.apache.org/cactus)来测试struts代码。
三.使用StrutsTestCase
在UT阶段,还是使用“模仿对象”方法进行测试Action类。
下面通过一个简单的使用Struts框架用户登录的例子,来简单介绍下StrutsTestCase的使用。
假设负责用户登录的LoginAction代码如下:
package strutstestcase;
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class LoginAction
extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse httpServletResponse) {
String username = ((LoginForm) form).getUsername();
String password = ((LoginForm) form).getPassword();
ActionErrors errors = new ActionErrors();
if ((!username.equals("yang")) || (!password.equals("yang")))
errors.add("password",new ActionError("error.password.mismatch"));
if (!errors.isEmpty()) {
saveErrors(request,errors);
return new ActionForward(mapping.getInput());
}
HttpSession session = request.getSession();
session.setAttribute("authentication", username);
// Forward control to the specified success URI
return mapping.findForward("success");
}
}
其他的LoginForm代码、登录JSP页、web.xml、struts-config.xml在此不再赘述,可参见附件。
下面来写LoginAction的测试类LoginActionTest:
package strutstestcase;
import servletunit.struts.*;
import junit.framework.*;
import java.io.File;
//测试类要继承MockStrutsTestCase类(也是TestCase类的子类)
public class TestLoginAction extends MockStrutsTestCase {
public TestLoginAction(String testName) {
super(testName);
}
public void setUp() throws Exception {
super.setUp();
//做一些初始化方面的工作,一定要让测试类找到web.xml、struts-config.xml,最好设置上下文的目录
this.setContextDirectory(new File("E:/exercise/project/StrutsTestCase/LoginDemo/"));
setInitParameter("validating","false");
}
public void testSuccessfulLogin() {
//根据struts-config.xml,设置要执行的actionMapping
setRequestPathInfo("/login");
//构造submit时要提交的数据
addRequestParameter("username","yang");
addRequestParameter("password","yang");
//执行Action类的execute()方法
actionPerform();
//验证返回是否正确
verifyForward("success");
verifyForwardPath("/success.jsp");
//验证session中的内容
assertEquals("yang",getSession().getAttribute("authentication"));
//验证是否有error
verifyNoActionErrors();
}
public void testFailedLogin() {
addRequestParameter("username","haha");
addRequestParameter("password","passwd");
setRequestPathInfo("/login");
actionPerform();
verifyForward("login");
verifyForwardPath("/login.jsp");
verifyInputForward();
verifyActionErrors(new String[] {"error.password.mismatch"});
assertNull(getSession().getAttribute("authentication"));
}
public static void main(String[] args) {
junit.textui.TestRunner.run(TestLoginAction.class);
}
}