StrutsTestCase测试Maven构建的Spring+Hibernate+Struts

用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也当作一个参数传入。

至于之后的测试方法的具体内容就很简单了,网上很多,千篇一律的。

相关推荐