一、JUnit5与Spring Boot Test
Spring Boot Test 是 Spring Boot 提供的测试框架,用于简化单元测试的编写过程。Spring Boot Test整合了许多JUnit5的特性,比如@ExtendWith,@Test,@Nested等。使用Spring Boot Test,我们可以做到“无环境”单元测试,即在不需要外部环境支持的情况下进行测试。
在使用Spring Boot Test时,需要引入spring-boot-starter-test依赖,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
对于单元测试,可以使用@SpringBootTest注解,表示加载整个Spring应用上下文。@SpringBootTest使用随机端口启动应用程序,可以使用@LocalServerPort注解注入随机端口值。
@SpringBootTest
public class MyTest {
@LocalServerPort
private int port;
private static final String URL_PREFIX = "http://localhost:";
@Test
public void test(){
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(URL_PREFIX + port + "/hello", String.class);
Assertions.assertEquals("hello", result);
}
}
二、Mockito进行依赖的Mock与Stub
Mockito是一个用于Java应用程序的单元测试框架,主要用于对依赖进行Mock或Stub。Mock指的是一个对象,并且根据需要返回预定义的输出。Stub指的是一个对象,如果根据需要返回预定义的输出,则执行代码的默认实现。
Mockito可以通过Mockito.mock()创建Mock对象。Mock对象只是一个空壳,它不会执行代码的默认实现,只会返回预先设置的值。Mockito使用when().thenReturn()设置预期返回值。
public class MyTest {
@Test
public void test(){
//创建Mock对象
MyDAO myDaoMock = Mockito.mock(MyDAO.class);
//设置预期返回值
when(myDaoMock.getDataById(1)).thenReturn("data1");
//调用被测方法,并验证返回值是否符合预期
MyService myService = new MyService(myDaoMock);
String result = myService.getDataById(1);
Assertions.assertEquals("data1", result);
//验证是否已经调用MyDAO的getDataById方法
verify(myDaoMock, times(1)).getDataById(1);
}
}
三、Testcontainers进行外部环境的集成测试
Testcontainers是一个Java库,可在本地或CI环境中运行Docker容器进行测试,用于进行外部环境的集成测试。
Testcontainers可与JUnit5和Spring Boot Test一起使用,只需在测试类中添加@Container和@DynamicPropertySource注解即可。@Container指示Testcontainers在测试之前运行Docker容器,@DynamicPropertySource则指定将动态分配的端口自动配置为Spring Boot 的配置文件中的属性。
@SpringBootTest
@ExtendWith(SpringExtension.class)
@Testcontainers
public class MyTest {
@Container
private static final MySQLContainer mysqlContainer = new MySQLContainer();
@DynamicPropertySource
static void mysqlProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", mysqlContainer::getJdbcUrl);
registry.add("spring.datasource.username", mysqlContainer::getUsername);
registry.add("spring.datasource.password", mysqlContainer::getPassword);
}
@Autowired
private MyRepository myRepository;
@Test
public void test(){
//测试代码
}
}
四、WebFlux测试
Spring Framework 5中引入的WebFlux是一种非阻塞、反应式编程风格的Web框架。对于WebFlux测试,可以使用spring-test库中的webTestClient实现。
webTestClient可以很容易地创建并发送请求,接收响应,并进行断言。webTestClient从中获得响应的Mono对象,可以通过subscribe方法阻塞响应。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
public class MyTest {
@Autowired
private WebTestClient webTestClient;
@Test
public void test(){
String result = webTestClient.get().uri("/hello")
.exchange().expectStatus().isOk()
.returnResult(String.class).getResponseBody().blockFirst();
Assertions.assertEquals("hello", result);
}
}
五、小结
Spring Boot Test是便于编写和执行测试用例的框架,支持单元测试、集成测试和WebFlux测试。Mockito用于测试中对依赖进行Mock或Stub,通过对依赖的预设行为,达到对实际业务场景的模拟测试。Testcontainers可以方便地测试运行在Docker容器中的外部环境,使测试用例更接近于实际生产环境。WebFlux基于异步非阻塞的编程模型,WebTestClient提供了对WebFlux应用的便捷测试支持。