关于单元测试的内容暂时也是在学习中,记录一下单元测试的用法,提供参考,只提供了些核心代码。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
标识 | 说明 |
---|---|
@BeforeAll | @BeforeAll 带注释的方法必须是测试类中的静态方法。在执行@Test 之前会优先执行这个方法,并且只执行一次 |
@BeforeEach | @BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。在执行@Test 之前会优先执行这个方法并且每次执行都会执行@BeforeEach 修饰的方法 |
@MockBean | 模拟一个Bean,是个壳子Bean,其行为和返回值可以用 Mockito.when(XXX).then(XXX)进行预设模拟 |
@DisplayName() | 执行时右侧名称展示,具体后面有图标明,可以配合@RepeatedTest() 注解使用 |
@RepeatedTest(5) | 重复执行5次 |
package com.example.unit.test.demo.service.impl;
import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.Calculator;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
/**
* @author 起凤
* @description: TODO
* @date 2022/7/6
*/
@Slf4j
@SpringBootTest
public class BeforeEachTest {
@MockBean
private OtherService otherService;
// BeforeAll 每个方法执行时,repeated时只会调用一次
@BeforeAll
public static void init() {
log.warn("BeforeAll Method init() method called");
}
// BeforeEach 每个方法执行时,repeated时只会调用多次
@BeforeEach
public void initEach() {
log.error("BeforeEach initEach() method called");
}
// DisplayName 执行时展示板上加个别名,看图
@DisplayName("Add operation test")
@RepeatedTest(5)
void addNumber(TestInfo testInfo, RepetitionInfo repetitionInfo) {
System.out.println("Running Test ->" + repetitionInfo.getCurrentRepetition());
Assertions.assertEquals(2, Calculator.add(1, 1), "1 + 1 should equal 2");
}
}
执行时能看到
@BeforeAll
最早执行,且只执行一次,@BeforeEach
每次重复都执行且先于重复体执行,@RepeatedTest(5)
标识后会执行5次,@DisplayName("Add operation test")
标识后重复执行里的左侧绿色的勾勾下的名称就叫Add operation test
DemoServiceTest.java
package com.example.unit.test.demo.service.impl;
import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.EchoRequest;
import com.example.unit.test.demo.controller.domain.EchoResponse;
import com.example.unit.test.demo.service.IDemoService;
import com.example.unit.test.demo.utils.SessionUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author 起凤
* @description: TODO
* @date 2022/7/6
*/
@SpringBootTest
class DemoServiceTest {
// 模拟外部调用需要进行Mock
@MockBean
private SessionUtils sessionUtils;
@MockBean
private OtherService otherService;
@Autowired
private IDemoService demoService;
// @BeforeAll 带注释的方法必须是测试类中的静态方法。
// 在执行@Test之前会优先执行这个方法
@BeforeAll
public static void beforeAll() {
System.out.println("BeforeAll init() method called");
}
// @BeforeEach 带注释的方法不能是静态方法,否则会抛出运行时错误。
// 对外请求和线程上下文相关行为进行Mock
@BeforeEach
public void beforeEach() {
// 进行提前mock 相当于当 sessionUtils.getCurrentUser() 被调用时就会返回 hello
Mockito.when(sessionUtils.getCurrentUser()).thenReturn("hello");
// 进行提前mock 相当于当 otherService.doSomething() 被调用时就会返回该入参时候的第0个参数
// 可以 Mockito.anyXXXX, 具体进入看源码,对请求入参的参数mock
Mockito.when(otherService.doSomething(Mockito.anyString()))
.thenAnswer((Answer<String>) invocationOnMock -> invocationOnMock.getArgument(0));
}
// 使用随机输入测试 Echo,这里demoService的echo方法内部有调用 OtherService的doSomething方法
// OtherService 已经被@MockBean修饰,且该方法提前在@BeforeEache里预设mock调用是是返回第一个入参
@Test
public void testEchoWithRandomInput() {
String input = UUID.randomUUID().toString();
EchoResponse resp = demoService.echo(EchoRequest.builder()
.input(input).build());
// 这里 resp.getOutput() == input正常不会抛出异常
Assertions.assertEquals(resp.getOutput(), input);
// 这里不一致会抛异常 resp.getOutput() 返回的是input 是一个UUID值
Assertions.assertEquals(resp.getOutput(), "1234");
}
@Test
void testSessionUtils() {
String currentUser = sessionUtils.getCurrentUser();
/// 下面这行打开会报错 前面设置了 sessionUtils调用getCurrentUser时返回 hello
// Assertions.assertEquals(currentUser,"hello1");
Assertions.assertEquals(currentUser, "hello");
String aaa = otherService.doSomething("aaa");
Assertions.assertEquals(aaa, "aaa1");
}
}
IDemoService.java
package com.example.unit.test.demo.service.impl;
import com.example.unit.test.demo.api.OtherService;
import com.example.unit.test.demo.controller.domain.EchoRequest;
import com.example.unit.test.demo.controller.domain.EchoResponse;
import com.example.unit.test.demo.service.IDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author 起凤
* @description: TODO
* @date 2022/7/6
*/
@Component
public class DemoService implements IDemoService {
@Autowired
private OtherService otherService;
@Override
public EchoResponse echo(EchoRequest request) {
return EchoResponse.builder()
.output(otherService.doSomething(request.getInput()))
.build();
}
}