第一次写博客,记录下今天学习Spring Test时遇到的问题。
一、问题描述
参照开涛博客在自己的项目上加入Spring Test,其网址为: http://jinnianshilongnian.iteye.com/blog/1469524
下面是我的控制层测试代码:
@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报错记录:
这是控制台输出的错误:
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";
}
}