SpringBoot in Action——测试

Spring的SpringJUnit4ClassRunner可以在基于JUnit的应用程序测试里加载Spring应用程序上下文。在测试Spring Boot应用程序时,Spring Boot除了拥有Spring的集成测试支持,还开启了自动配置和Web服务器,并提供了不少实用的测试辅助工具。

集成测试自动配置

我们以前Spring的测试是这样的:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes=AddressBookConfiguration.class)
public class AddressServiceTests {
	@Autowired
	private AddressService addressService;
	@Test
	public void testService() {
		Address address = addressService.findByLastName("Sheman");
		assertEquals("P", address.getFirstName());
		assertEquals("Sherman", address.getLastName());
		assertEquals("42 Wallaby Way", address.getAddressLine1());
		assertEquals("Sydney", address.getCity());
		assertEquals("New South Wales", address.getState());
		assertEquals("2000", address.getPostCode());
	}
}

如你所见,AddressServiceTests上加注了@RunWith和@ContextConfiguration注解。@RunWith的参数是SpringJUnit4ClassRunner.class,开启了Spring集成测试支持。
虽然@ContextConfiguration在加载Spring应用程序上下文的过程中做了很多事情,但它没能加载完整的Spring Boot。Spring Boot应用程序最终是由SpringApplication加载的。它可以显式加载,在这里也可以使用SpringBootServletInitializer。
SpringApplication不仅加载应用程序上下文,还会开启日志、加载外部属性(application.properties或application.yml),以及其他Spring Boot特性。用@ContextConfiguration则得不到这些特性。

要在集成测试里获得这些特性,可以把@ContextConfiguration替换为Spring Boot的@SpringApplicationConfiguration:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
	classes=AddressBookConfiguration.class)
public class AddressServiceTests {
...
}

测试Web应用程序

Spring MVC有一个优点:它的编程模型是围绕POJO展开的,在POJO上添加注解,声明如何处理Web请求。这种编程模型不仅简单,还让你能像对待应用程序中的其他组件一样对待这些控制器。你还可以针对这些控制器编写测试,就像测试POJO一样。
举例来说,考虑ReadingListController里的addToReadingList()方法:

@RequestMapping(method=RequestMethod.POST)
public String addToReadingList(Book book) {
	book.setReader(reader);
	readingListRepository.save(book);
	return "redirect:/readingList";
}

如果忽略@RequestMapping注解你得到的就是一个相当基础的Java方法你立马就能想到这样一个测试提供一个ReadingListRepository的模拟实现,直接调用addToReading-List(),判断返回值并验证对ReadingListRepository的save()方法有过调用。

当然,requestMapping不能忽略。该测试的问题在于,它仅仅测试了方法本身,当然,这要比没有测试好一点。然而,它没有测试该方法理/readingList的POST请求的情况,也没有测试表单域绑定到Book参数的情况。

要恰当地测试一个Web应用程序,你需要投入一些实际的HTTP请求,确认它能正确地处理那些请求。幸运的是,Spring Boot开发者有两个可选的方案能实现这类测试。

  • Spring Mock MVC:能在一个近似真实的模拟Servlet容器里测试控制器,而不用实际启动应用服务器。
  • Web集成测试:在嵌入式Servlet容器(比如Tomcat或Jetty)里启动应用程序,在真正的应用服务器里执行测试。

这两种方法各有利弊。很明显,启动一个应用服务器会比模拟Servlet容器要慢一些,但毫无疑问基于服务器的测试会更接近真实环境,更接近部署到生产环境运行的情况。

模拟Spring Mvc
Spring的Mock MVC框架模拟了Spring MVC的很多功能。它几乎和运行在Servlet容器里的应用程序一样。
我们以前已经介绍过Mock,对此不再做介绍了。

测试运行中的应用程序
用真实的Web浏览器在真实的服务器上运行测试会很麻烦。虽然构建时的插件能把应用程序部署到Tomcat或者Jetty里,但它们配置起来多有不便。而且测试这么多,几乎不可能隔离运行,也很难不启动构建工具。

然而Spring Boot找到了解决方案。它支持将Tomcat或Jetty这样的嵌入式Servlet容器作为运行中的应用程序的一部分,可以运用相同的机制,在测试过程中用嵌入式Servlet容器来启动应用程序。

Spring Boot 的@WebIntegrationTest 注解就是这么做的。在测试类上添加@WebIntegrationTest注解,可以声明你不仅希望Spring Boot为测试创建应用程序上下文,还要启动一个嵌入式的Servlet容器。一旦应用程序运行在嵌入式容器里,你就可以发起真实的HTTP请求,断言结果了。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
	classes=ReadingListApplication.class)
@WebIntegrationTest
public class SimpleWebTest {
	@Test(expected=HttpClientErrorException.class)
	public void pageNotFound() {
		try {
			RestTemplate rest = new RestTemplate();
			rest.getForObject(
				"http://localhost:8080/bogusPage", String.class);
			fail("Should result in HTTP 404");
		} catch (HttpClientErrorException e) {
			assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode());
			throw e;
		}
	}
}

另外@WebIntegrationTest("server.port=0")可以使用随机端口打开,避免其他应用也使用8080端口。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值