Spring Test + Struts2 Convention 控制层单元测试

第一次写博客,记录下今天学习Spring Test时遇到的问题。

一、问题描述

下面是我的控制层测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public class LoginActionTest extends StrutsSpringTestCase {
	
	/**
	 * 默认路径
	 * classpath*:applicationContext.xml
	 * @throws Exception
	 */
	@Override
	protected String[] getContextLocations() {
		return new String[]{"classpath:applicationContext.xml"};
	}
	
	@Before  
    public void setUp() throws Exception {  
        //1 指定Struts2配置文件  
        //该方式等价于通过web.xml中的<init-param>方式指定参数  
        Map<String, String> dispatcherInitParams = new HashMap<String, String>();  
        ReflectionTestUtils.setField(this, "dispatcherInitParams", dispatcherInitParams);  
        //1.1 指定Struts配置文件位置  
        dispatcherInitParams.put("config", "struts-default.xml,struts-plugin.xml,struts.xml");  
        super.setUp();  
    }  

	/**
	 * @throws Exception 
	 * 
	 */
	@Test
	public void testWelcome() throws Exception {
		String output = executeAction("/user/login!welcome.action");
        assertEquals(Action.SUCCESS, output);
	}
	
	@Test
	public void testDeal() throws Exception {
		request.setParameter("username", "张三");
		request.setParameter("password", "1");
		
		ActionProxy proxy = getActionProxy("/user/login!deal.action");
        assertNotNull(proxy);
        
        LoginAction action = (LoginAction) proxy.getAction();
        assertNotNull(action);
        String result = proxy.execute();
        assertNull(result);
        
//        String username = (String) findValueAfterExecute("username");
//        String password = (String) findValueAfterExecute("password");
//        assertEquals("张三", username);
//        assertEquals("1", password);
        System.out.println(response.getContentAsString());
        assertEquals("张三", action.getModel().getUsername());
        assertEquals("1", action.getModel().getPassword());
	}

}

下面是JUnit4报错记录:

 Spring Test + Struts2 Convention 控制层单元测试

这是控制台输出的错误:

2016-01-21 15:18:09,848  WARN (org.springframework.mock.web.MockServletContext:319) - Couldn't get resource paths for class path resource [WEB-INF/jsp/user/]
java.io.FileNotFoundException: class path resource [WEB-INF/jsp/user/] cannot be resolved to URL because it does not exist
	at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187)
	at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:48)
	at org.springframework.mock.web.MockServletContext.getResourcePaths(MockServletContext.java:303)
	at org.apache.struts2.convention.DefaultResultMapBuilder.createFromResources(DefaultResultMapBuilder.java:252)
	at org.apache.struts2.convention.DefaultResultMapBuilder.build(DefaultResultMapBuilder.java:189)
	at org.apache.struts2.convention.PackageBasedActionConfigBuilder.createActionConfig(PackageBasedActionConfigBuilder.java:933)
	at org.apache.struts2.convention.PackageBasedActionConfigBuilder.buildConfiguration(PackageBasedActionConfigBuilder.java:702)
	at org.apache.struts2.convention.PackageBasedActionConfigBuilder.buildActionConfigs(PackageBasedActionConfigBuilder.java:348)
	at org.apache.struts2.convention.ClasspathPackageProvider.loadPackages(ClasspathPackageProvider.java:53)
	at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:268)
	at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
	at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:445)
	at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:489)
	at org.apache.struts2.util.StrutsTestCaseHelper.initDispatcher(StrutsTestCaseHelper.java:54)
	at org.apache.struts2.StrutsTestCase.initDispatcher(StrutsTestCase.java:229)
	at org.apache.struts2.StrutsTestCase.setUp(StrutsTestCase.java:209)
	at web.user.LoginActionTest.setUp(LoginActionTest.java:47)

二、解决方法

参照http://blog.csdn.net/jammiwang19870815/article/details/9175607添加自己的ResourceLoader,即可解决,在写的时候注意ResourceLoader路径问题,要与真实路径一致,下面是我的代码:

public class MyResourceLoader extends DefaultResourceLoader {
	private static final Logger logger = LoggerFactory.getLogger(MyResourceLoader.class);

	@Override
	public Resource getResource(String location) {
		if(location != null && location.startsWith("/WEB-INF/")) {
			logger.info(location);
			URL path = null;
			try {
				String str = "file:/" + System.getProperty("user.dir") + "/WebRoot" + location;
				logger.info(str);
				path = new URL(str);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
			return new UrlResource(path);
		}
		return super.getResource(location);
	}
	
}

其中评论中提到另一个解决方案:

log4j.properties中添加:log4j.logger.org.springframework.mock.web.MockServletContext=error

该方法只是屏蔽了控制台的输出,但是测试还是没有通过,所以是不行的!

三、总结

1、为何testDeal()测试方法通过,而testWelcome()测试方法没有通过呢?

其原因是:testDeal()对应的LoginAction deal()方法return为null,而testWelcome()对应的LoginAction  welcome()方法return为success,会对应WEB-INF/jsp/user/login.jsp,由于它默认是查找classpath下的路径,所以找不到报错,这就是为什么要重写ResourceLoader的原因。

说明:这个是否出错与你写的Action有关,只是本例是这么写的。

2、getContextLocations默认查找的是classpath*:applicationContext.xml,所以本例中的getContextLocations()方法可以不复写。

3、若测试类不添加@RunWith(SpringJUnit4ClassRunner.class) @TestExecutionListeners({})注解则不能使用@Ignore忽略测试,而且默认是所有方法都进行测试,即默认添加了@Test注解,但是加了前面两个注解后,JUnit4的注解都能正常使用,目前还不明白是为何?

附录

最后再把LoginAction补齐:

@SuppressWarnings("serial")
@Namespace("/user")
public class LoginAction extends StrutsAction<User> {
	
	@Autowired
	private UserService userService;
	
	public String welcome() {
		logger.info("登录页面");
		return SUCCESS;
	}
	
	/**
	 * 登录
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public String deal() throws UnsupportedEncodingException {
		Result result = null;
		boolean flag = userService.exist(model.getUsername());
		if(flag) {//登录
			flag = userService.exist(model);
			if(flag) {
				//保存user对象到session中
				Map<String, Object> session = ActionContext.getContext().getSession();
				session.put("username", model.getUsername());
				String resultUrl = Struts2Utils.getRequest().getContextPath() + "/main.action";
				result = new Result(Result.SUCCESS, "", resultUrl);
			} else {
				result = new Result(Result.ERROR, "密码错误", "");
			}
		} else {
			result = new Result(Result.ERROR, "用户不存在", "");
		}
		Struts2Utils.renderText(result);
		return null;
	}
	
	/**
	 * 退出
	 * @return
	 */
	public String logout() {
		Map<String, Object> session = ActionContext.getContext().getSession();
		session.remove("username");
		return "logout";
	}

	
}

相关推荐