参考文章:Spring MVC全注解配置 - 无web.xml


单元测试的目的,简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改bug),都可以做到重新测试的工作。以减少我们在发布的时候出现更过甚至是出现之前解决了的问题再次重现。


Spring MVC的测试往往看似比较复杂。其实他的不同在于,他需要一个ServletContext来模拟我们的请求和响应。但是Spring也针对Spring MVC 提供了请求和响应的模拟测试接口,以方便我们的单元测试覆盖面不只是service,dao层。


我们会结合上一篇文章的配置进行junit的测试。上一篇文章中我们使用纯java代码来配置spring mvc,因此在我们书写junit测试的时候,有三点需要注意,这个和平时的junit测试有点不同

  1. 在测试类上的@ContextConfiguration注解需要指定spring的配置文件,由于我们使用的是java配置,所以这里传递我们的配置类,记住是spring的配置类,而不是web的配置类(注:web的配置我们是通过模拟的)。

  2. 因为controller,component等都是使用注解来,所以我们的@ContextConfiguration使用的是直接来加载的。因此在他的属性中,配置一个loader。同时由于是web的,所以使用AnnotationConfigWebContextLoader

  3. 由于需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration


代码如下:

@RunWith(Parameterized.class)
@ContextConfiguration(classes = { WebMVCConfiguration.class }, loader = AnnotationConfigWebContextLoader.class)
@WebAppConfiguration
public class ControllerTest

我的目的是使用参数化来测试controller,所以使用的是@RunWith是参数化的runner。由于junit的runner只能有一个,所以我们这里用另外的方式来让spring的功能也集成进来。


下面一步就是编写我们的测试controller,代码如下:

@Controller
public class TestController {
	@RequestMapping(value = "/test", method = RequestMethod.GET)
	public @ResponseBody String test(String name) {
		return name;
	}
}

在我们的测试类中,我们就正对此Controller的方法进行一个参数的构造。


Junit中参数构造这里就不多讲,@Parameters来标记数据集合,私有属性和构造函数来对应我们的传入参数与预期结果。因此在ControllerTest中我们这样构造数据:

// parameters
private String name;
private String result;

public ControllerTest(String name, String result) {
	this.name = name;
	this.result = result;
}

@Parameters
public static Collection<String[]> data() {
	return Arrays.asList(new String[][] { { "Troy", "Troy" },
			{ "Young", "Young" } });
}


在模拟http request response之前我们需要去模拟一个request和response的环境,同时也要让我们的spring的功能融入进来,这样才能方便我们使用spring的DI等功能。因此这两个都在我们test之前进行配置:

private TestContextManager testContextManager;

private MockMvc mockMvc;

@Autowired
private WebApplicationContext wac;

@Before
public void setUp() throws Exception {
	testContextManager = new TestContextManager(getClass());
	testContextManager.prepareTestInstance(this);

	mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}

此时我们已经具备了环境、参数,接下里就进行真正的测试代码的编写:

@Test
public void test() throws Exception {
	MvcResult rs = mockMvc.perform(
			MockMvcRequestBuilders.get("/test?name=" + name)).andReturn();
	assertEquals("name is not correct", result, new String(rs.getResponse()
				.getContentAsByteArray()));
}


能够很好的运行起来,已经达到我们预期的效果。以后的扩展就只用在data里面去进行扩展配置参数,然后每一次build的时候我们都可以发现我们的build存在bug么。


很多具体的类使用请自行查阅一下。本文只是讲解简单的操作。