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。