经过前面几次文章的分享的 UT 的相关知识,今天接着分享 UT 相关最后一测文章,希望对大家在 UT 的学习中有一点点的帮助。
Spring 集成测试
有时候我们需要在跑起来的 Spring 环境中验证,Spring 框架提供了一个专门的测试模块(spring-test),用于应用程序的集成测试。
在 Spring Boot 中,你可以通过 spring-boot-starter-test 启动器快速开启和使用它。
这时首先就有了 Spring 容器运行环境,就可以模拟浏览器调用等操作
引入测试坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency><dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.19.0</version> <scope>test</scope></dependency>
复制代码
为了与生产环境配置区分开
新建一个 application-test.yml
server: port: 8088 spring: application: name: hello-service-for-test
复制代码
controller 类,也就是被测对象
@RestControllerpublic class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello() throws Exception { return "Hello World"; }}
复制代码
测试方案一
通过 TestRestTemplate 模拟调用 Rest 接口
@ExtendWith(SpringExtension.class)@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)@ActiveProfiles("test")class HelloControllerTest {
@Autowired private TestRestTemplate restTemplate;
@Value("${spring.application.name}") private String appName;
@BeforeEach void setUp() { assertThat(appName).isEqualTo("hello-service-for-test"); }
@Test void testHello() throws Exception { String response = restTemplate.getForObject("/hello", String.class);
assertThat(response).isEqualTo("Hello World"); }}
复制代码
测试方案二
通过 MockMvc 来调用 Rest 接口
@ExtendWith(SpringExtension.class)@SpringBootTest@AutoConfigureMockMvc@ActiveProfiles("test")class HelloControllerTest {
@Autowired private HelloController helloController;
@Autowired private MockMvc mockMvc;
@Value("${spring.application.name}") private String appName;
@BeforeEach void setUp() { assertThat(appName).isEqualTo("hello-service-for-test"); }
@Test void testHello() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/hello")) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("Hello World")); }}
复制代码
方案一会启动 Spring 容器,相对更符合我们测试思路,建议选用此方案测试
方案二不会启动内置的容器,所以耗时相对少一点
与 Spring 类似 dropwizard 也有一套测试方案,可以提供 Jetty 容器来做集成测试
Dropwizard 集成测试
引入 maven 坐标
<dependency> <groupId>io.dropwizard</groupId> <artifactId>dropwizard-testing</artifactId> <version>2.0.21</version> <scope>test</scope></dependency><dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.6.2</version> <scope>test</scope></dependency><dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.19.0</version> <scope>test</scope></dependency>
复制代码
被测试资源类
@Path("/ping")@Servicepublic class PingResource { @GET public String ping() { return "pong"; }}
复制代码
测试方案一
不启动 Jetty 容器,通过 ResourceExtension 扩展测试
@ExtendWith(DropwizardExtensionsSupport.class)class PingResourceTest {
private static final ResourceExtension EXT = ResourceExtension.builder() .addResource(new PingResource()) .build();
@Test void should_get_pong_when_send_ping() { String response = EXT.target("/ping").request().get(String.class);
assertThat(response).isEqualTo("pong"); }}
复制代码
测试方案二
通过启动 Jetty 容器测试,为了避免项目中的循环依赖关系或加快测试运行速度,可以通过将 JAX-RS 资源编写为测试DropwizardClientExtension来测试 HTTP 客户端代码,并启动和停止包含测试的简单 Dropwizard 应用程序。
@ExtendWith(DropwizardExtensionsSupport.class)class PingResourceTest3 {
private static final DropwizardClientExtension EXT = new DropwizardClientExtension(new PingResource());
@Test void should_get_pong_when_send_ping() throws IOException { URL url = new URL(EXT.baseUri() + "/ping"); System.out.println(url.toString()); String response = new BufferedReader(new InputStreamReader(url.openStream())).readLine();
assertThat(response).isEqualTo("pong"); }}
复制代码
测试方案三
通过指定 yml 配置文件,Jersey HTTP client 调用 Rest 接口, 返回的客户端可以在测试之间重用
在 JUnit5 测试类中添加DropwizardExtensionsSupport注释和DropwizardAppExtension扩展名将在运行任何测试之前启动应用程序
并在测试完成后再次停止运行(大致等同于使用@BeforeAll和@AfterAll)
DropwizardAppExtension也暴露了应用程序的Configuration, Environment并且应用程序对象本身,使这些可以通过测试进行查询。
新增配置文件\src\test\resources\hello.yml
server: type: simple rootPath: '/api/*' applicationContextPath: / connector: type: http port: 9090
复制代码
测试:
@ExtendWith(DropwizardExtensionsSupport.class)class PingResourceTest2 {
private static DropwizardAppExtension<HelloWorldServiceConfiguration> EXT = new DropwizardAppExtension<>( HelloWorldServiceApp.class, ResourceHelpers.resourceFilePath("hello.yml") );
@Test void should_get_pong_when_send_ping() { Client client = EXT.client(); String response = client.target( String.format("http://localhost:%d/api/ping", EXT.getLocalPort())) .request() .get(String.class);
assertThat(response).isEqualTo("pong"); }}
复制代码
参考
https://www.dropwizard.io/en/latest/manual/testing.html#
前文传送门
1、工作多年后我更了解了UT的重要性
2、五年了,你还在用junit4吗?
评论