Spring与Struts结合测试的有关问题解答
JDK1.6都出来好长时间了,可我现在公司开发用的还是jdk1.4,说是稳定,另外一个,公司的用户都不愿意花钱升级自己的应用服务器,所以,我们只能在JDK1.4下面开发。另外公司的架构是一个技术牛人写的,采用Struts1.2+spring2.0,前台JSP页面展示采用一套自己的验证,数据传递到后台以及持久层都是那个牛人写的,公用框架没问题,也比较好用,但是缺乏测试。
我针对持久层写了一些测试,但是对struts的Action层一直没有测试,从网上搜索出来的东西,大都是专门真么SPring或者专门针对Struts的,或者有针对Spring+struts的,但是就一个简单的Demo,对于路径问题,还是没有解决,总是报404或者其他的错误,最终花了好几天的时间,才搞定这个问题,特写博客记录一下,也希望能给有需要这方面东西的朋友提供个帮助。
其实例子就是简单的一个登录功能,登录成功后进入dwgl模块,包含两个struts的action类,一个在根目录下,一个在dwgl路径下。
web.xml主要配置如下:
<servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/config/struts-config.xml</param-value> </init-param> <init-param> <param-name>config/dwgl</param-name> <param-value>/WEB-INF/config/struts-config-dwgl.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
其中Spring通过Struts的ContextLoaderPlugIn插件形式加载,项目中有连个Struts的配置文件以及两个spring的配置文件,都存放在WEB-INF/config/目录下面,文件名分别是struts-config.xml、struts-config-dwgl.xml、applicationContext.xml、applicationContext-dwgl.xml。
struts-config.xml内容如下:
<struts-config> <action-mappings> <action input="/login.jsp" path="/login" type="org.springframework.web.struts.DelegatingActionProxy"> <forward name="success" path="/WEB-INF/jsp/success.jsp" /> </action> </action-mappings> <message-resources parameter="com.accp.web.struts.ApplicationResources" /> <!-- 注意,加载Spring插件contextConfigLocation参数必须写成下面的形式,即多个参数之间用逗号隔开, 如果写成applicationContext*.xml的形式,对action层进行测试时候会出现空指针的错误 --> <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/config/applicationContext.xml,/WEB-INF/config/applicationContext-dwgl.xml" /> </plug-in> </struts-config>
struts-config-dwgl.xml内容如下:
<struts-config> <action-mappings> <action path="/dwgl" parameter="method" type="org.springframework.web.struts.DelegatingActionProxy"> <forward name="success" path="/WEB-INF/jsp/success.jsp" /> </action> </action-mappings> </struts-config>
applicationContext.xml内容如下:
<beans> <bean name="/login" class="com.accp.web.struts.action.LoginAction"/> </beans>
applicationContext-dwgl.xml内容如下:
<beans>
<bean name="/dwgl/dwgl" class="com.accp.web.struts.action.dwgl.DwglAction"/>
</beans>
具体loginAction内容就是一个简单的提交,
java代码:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { String userName = request.getParameter("userName"); ActionMessages errors = new ActionMessages(); if (userName == null || userName.length() == 0) { errors.add("userName", new ActionMessage("errors.userName")); } if (errors.size() > 0) { saveErrors(request, errors); return mapping.getInputForward(); } request.setAttribute("userName", userName); return mapping.findForward("success"); }
dwglAction继承DispatchAction,内容如下:
public class DwglAction extends DispatchAction {
public ActionForward querydw(ActionMapping arg0, ActionForm arg1,
HttpServletRequest arg2, HttpServletResponse arg3) throws Exception {
return null;
}
}
在这里我只想测试能不能执行到方法内部,所以方法里面也没有什么逻辑处理。
完了写LoginAction的测试,继承自MockStrutsTestCase,但是由于action是Spring进行管理的,所以要写一个将Spring的webapplicationcontext添加到servletcontex中,这里通过SpringWebContextHelper类完成,具体内容为:
public class SpringWebContextHelper { private static XmlWebApplicationContext wac = null; public static void setWebApplicationContext(ServletContext context) { if (context .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { return; } if(wac == null){ wac = new XmlWebApplicationContext(); wac.setServletContext(context); URL classUrl = SpringWebContextHelper.class.getResource(""); String path = classUrl.getPath(); try { path = URLDecoder.decode(path, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } path = path.substring(0 , path.indexOf("WEB-INF")) + "WEB-INF/"; File configPath = new File(path + "config/"); String[] applicationContexts = configPath.list(new FilenameFilter(){ public boolean accept(File dir, String name){ if(name.toLowerCase().startsWith("applicationcontext")){ return true; } return false; } }); for(int i=0;i<applicationContexts.length;i++){ applicationContexts[i] = path + "config/" + applicationContexts[i]; } wac.setConfigLocations(applicationContexts); wac.refresh(); } context.setAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); } }
LoginActionTest 类代码如下:具体注释写的很清楚,大家一看就明白,
public class LoginActionTest extends MockStrutsTestCase {
public void setUp() throws Exception
{
super.setUp(); //调用父类的setUp()
setContextDirectory(new File("WebRoot")); //指定上下文目录(WEB-INF的父目录)
// this.setConfigFile("/WEB-INF/config/struts-config.xml,/WEB-INF/config/struts-config-dwgl.xml");
this.setConfigFile("/WEB-INF/config/struts-config.xml");
this.setConfigFile("dwgl","/WEB-INF/config/struts-config-dwgl.xml");
SpringWebContextHelper.setWebApplicationContext(context);
}
//验证1:在给出正确参数的前提下,是否会返回名为success的ActionForward,以及作用域中是否有正确的数据?
public void testSuccess()
{
//选择要执行哪一个Action
this.setRequestPathInfo("/login.do");
//指定请求参数
this.addRequestParameter("userName", "ACCP");
//下面这个方法其实就是调用Action中的execute()方法,呵呵。
this.actionPerform();
//验证返回是否正确(登录名不为空,应该返回"success")
this.verifyForward("success");
//验证“作用域”中的数据是否符合要求
String expected = "ACCP";
Object actual = this.getRequest().getAttribute("userName");
assertEquals(expected, actual);
}
//验证2:在不给参数的前提下,是否会返回相关的错误消息?
public void testFailure()
{
this.setRequestPathInfo("/login.do");
this.actionPerform();
this.verifyInputForward();
this.verifyActionErrors(new String[]{ "errors.userName" });
}
}
由于dwglaction继承自 DispatchAction ,并且在dwgl模块下,所以测试类路径设置以及方法设置要复杂一点,具体代码如下:
public class DwglActionTest extends MockStrutsTestCase {
public void setUp() throws Exception {
super.setUp(); // 调用父类的setUp()
setContextDirectory(new File("WebRoot/")); // 指定上下文目录(WEB-INF的父目录)
String configfilePath = "/WEB-INF/config/struts-config.xml";
this.setConfigFile(configfilePath);
//第一个参数子项目的配置文件,不能以"/"开头
this.setConfigFile("dwgl","/WEB-INF/config/struts-config-dwgl.xml");
SpringWebContextHelper.setWebApplicationContext(context);
setInitParameter("validating","false");
}
public void testGetMessage() {
// 选择要执行哪一个Action,其中第一个参数用来标识子项目,切记必须以“/”开头
this.setRequestPathInfo("/dwgl","/dwgl.do");
this.addRequestParameter("method", "querydw");
this.actionPerform();
}
public static void main(String[] args){
}
}
现在写完这些测试方法,感觉好简单,可当时却折磨得我好苦,花了好几天的时间才完成这些测试,当时由于一个路径设置的问题,junit的进度条就是不能变绿,等到最后完成这些测试、进度条变绿,我才舒了一口气,希望对需要的朋友有一些帮助。
附件为所有的源代码,不过由于lib文件太大,我没有进行上传,具体需要以下jar包,log4j、struts、spring、strutstest。