用maven构建了一个simple java web application。目录结构都按照maven默认定义的设置。
由于ApplicationContext.xml 存放着resources目录下,引起了很多spring配置文件找不到的问题。这些今天就不说了。先说今天的事。
我们在用StrutsTestCase对Struts进行单元测试的时候出现过ApplicationContext.xml 找不到的问题,控制台打印如下:
servletunit.struts.ExceptionDuringTestError: An uncaught exception was thrown during actionExecute()
at servletunit.struts.MockStrutsTestCase.actionPerfor m(MockStrutsTestCase.java:409)
at test.struts.action.StrutsLogonTest.testExecuteActi onMappingActionFormHttpServletRequestHttpServletRe sponse(StrutsLogonTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154 )
at junit.framework.TestCase.runBare(TestCase.java:127 )
at junit.framework.TestResult$1.protect(TestResult.ja va:106)
at junit.framework.TestResult.runProtected(TestResult .java:124)
at junit.framework.TestResult.run(TestResult.java:109 )
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:2 08)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.main(RemoteTestRunner.java:186)
------------
Root Cause:
------------
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplica tionContextUtils.getRequiredWebApplicationContext( WebApplicationContextUtils.java:83)
at org.springframework.web.struts.DispatchActionSuppo rt.initWebApplicationContext(DispatchActionSupport .java:102)
at org.springframework.web.struts.DispatchActionSuppo rt.setServlet(DispatchActionSupport.java:78)
at org.apache.struts.action.RequestProcessor.processA ctionCreate(RequestProcessor.java:297)
at org.apache.struts.action.RequestProcessor.process( RequestProcessor.java:220)
at org.apache.struts.action.ActionServlet.process(Act ionServlet.java:1164)
at org.apache.struts.action.ActionServlet.doPost(Acti onServlet.java:415)
at servletunit.struts.MockStrutsTestCase.actionPerfor m(MockStrutsTestCase.java:394)
at test.struts.action.StrutsLogonTest.testExecuteActi onMappingActionFormHttpServletRequestHttpServletRe sponse(StrutsLogonTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154 )
at junit.framework.TestCase.runBare(TestCase.java:127 )
at junit.framework.TestResult$1.protect(TestResult.ja va:106)
at junit.framework.TestResult.runProtected(TestResult .java:124)
at junit.framework.TestResult.run(TestResult.java:109 )
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:2 08)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.main(RemoteTestRunner.java:186)
但是我在web.xml里确实是已经registe the spring ContextLoaderListener了。
郁闷了半天。
这里不得不说一下StrutsTestCase的运行机制了。
StrutsTestCase for JUnit是Junit TestCase类的扩展,提供基于Struts框架的代码测试装置。StrutsTestCase同时提供Mock 对象方法和Cactus方法用来实际运行Struts ActionServlet,你既可以通过运行servlet引擎来测试,也可以不通过它。因为StrutsTestCase使用ActionServlet控制器来测试你的代码,因此你不仅可以测试Action对象的实现,而且可以测试mappings,from beans以及forwards声明。
使用StrutsTestCase不启动servlet容器来测试struts应用程序(容器外测试)也属于Mock对象测试,但是与EasyMock不同的是,EasyMock是提供了创建Mock对象的API,而StrutsTest则是专门负责测试Struts应用程序的Mock对象测试框架。
由于我们这里是通过spring来管理struts的,所以我们这里所要面临的一个主要的问题就是要提供一个ApplicationContext为TestCase调用,这样我们引用了一个JUnitHelper工具类进行相关Spring的操作,如提供ApplicationContext环境,下面我们就实现类测试和Action类测试进行一下讲解,其中数据库连接由spring控制。由于每一个测试类中都要用到所提供的ApplicationContext环境。所以我专门为此写了一个辅助的类JUnitHelper用来取ApplicationContext环境.在MockStrutsTestCase的setup方法中,我们进行绑定操作: JUnitHelper.setWebApplicationContext(getActionServlet().getServletContext()) ; 就可以了。
具体JUnithelper.java类的代码如下:
package com.ninetowns.mes.action;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class JUnitHelper {
public static String BASE_DIRECTORY = "";
public static String[] Configuration_Location;
private static XmlWebApplicationContext wac = null;
private static FileSystemXmlApplicationContext fsxac = null;
static {
initPath();
}
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);
wac.setConfigLocations(Configuration_Location);
wac.refresh();
}
context.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
wac);
}
public static ApplicationContext getApplicationContext() {
if (fsxac == null) {
fsxac = new FileSystemXmlApplicationContext(Configuration_Location);
}
return fsxac;
}
public static void initPath() {
try {
BASE_DIRECTORY = new File(".").getCanonicalPath();
Configuration_Location = new String[] {
BASE_DIRECTORY + "/src/main/resources/applicationContext-actions.xml",
BASE_DIRECTORY + "/src/main/resources/applicationContext-beans.xml",
BASE_DIRECTORY + "/src/main/resources/applicationContext-common.xml" };
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试类如下:
package com.ninetowns.mes.action;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.springframework.web.context.support.XmlWebApplicationContext;
import com.ninetowns.mes.manager.tqs.TQSConfigurationLoader;
import com.ninetowns.mes.model.tqs.TQSItem;
import com.ninetowns.mes.util.MesMap;
import servletunit.struts.MockStrutsTestCase;
public class TestModifyAction extends MockStrutsTestCase {
public void setUp() throws Exception {
super.setUp();
setContextDirectory(new File("src/main/webapp"));
JUnitHelper.setWebApplicationContext(getActionServlet()
.getServletContext());
setInitParameter("validating", "false");
}
public void tearDown() throws Exception {
super.tearDown();
}
public void testModifyAction() throws Exception {
setRequestPathInfo("/add");
addRequestParameter("method", "edit");
actionPerform();
verifyForward("addpage");
}
}
setContextDirectory(new File("src/main/webapp"));
这个是在src/main/webapp下查找struts-config.xml(因为我用的是maven构建的项目,所以struts配置文件在那)
JUnitHelper.setWebApplicationContext(getActionServlet().getServletContext());
这就上面说的获得Spring 的ApplicationContext。
还有一点我的Action是用的是DispatchAction,故而要加上
addRequestParameter("method", "edit");
把method也当作一个参数传入。
至于之后的测试方法的具体内容就很简单了,网上很多,千篇一律的。