之前写过一篇使用testMe自动生成单元测试用例,使用的是junit4来编写的单元测试用例,目前很多新项目都已经使用JDK11+以及SpringBoot3+。本次基于junit5+Mockito来编写单元测试。
SpringBoot依赖
org.springframework.boot
spring-boot-starter-parent
3.1.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.objenesis
objenesis
mockito依赖
org.mockito
mockito-junit-jupiter
5.3.1
org.mockito
mockito-core
5.3.1
lombok依赖
org.projectlombok
lombok
edge-SNAPSHOT
SpringBoot依赖
org.springframework.boot
spring-boot-starter-parent
2.2.5.RELEASE
Junit依赖
org.junit.jupiter
junit-jupiter
5.8.2
mockito依赖
org.mockito
mockito-core
5.2.0
net.bytebuddy
byte-buddy
net.bytebuddy
byte-buddy-agent
org.mockito
mockito-junit-jupiter
5.2.0
net.bytebuddy
byte-buddy
1.14.1
net.bytebuddy
byte-buddy-agent
1.14.1
lombok依赖
org.projectlombok
lombok
1.18.30
package com.summer.toolkit.mock;
import com.alibaba.fastjson.JSON;
import com.summer.toolkit.dto.UserDto;
import com.summer.toolkit.exception.BizException;
import com.summer.toolkit.executor.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserManager userManager;
@Override
public Long createUser(UserDto userDto) {
log.info("创建用户入参:{}", JSON.toJSONString(userDto));
String name = userDto.getUsername();
if (StringUtils.isBlank(name)) {
log.error("用户名称不能为空");
throw new BizException("用户名称不能为空");
}
Long id = userManager.createUser(userDto);
log.info("创建用户出参:{}", id);
return id;
}
@Override
public Boolean updateUser(UserDto userDto) {
log.info("更新用户入参:{}", JSON.toJSONString(userDto));
Long id = userDto.getId();
String name = userDto.getUsername();
if (Objects.isNull(id)) {
log.error("用户主键不能为空");
throw new BizException("用户主键不能为空");
}
if (StringUtils.isBlank(name)) {
log.error("用户名称不能为空");
throw new BizException("用户名称不能为空");
}
UserDto user = userManager.getUser(userDto);
if (Objects.isNull(user)) {
log.error("用户不存在");
throw new BizException("用户不存在");
}
Boolean result = userManager.updateUser(userDto);
log.info("更新用户出参:{}", result);
return result;
}
@Override
public UserDto getUser(UserDto userDto) {
log.info("获取用户入参:{}", JSON.toJSONString(userDto));
Long id = userDto.getId();
if (Objects.isNull(id)) {
log.error("用户主键不能为空");
throw new BizException("用户主键不能为空");
}
UserDto user = userManager.getUser(userDto);
log.info("获取用户出参:{}", user);
return user;
}
@Override
public Boolean batchCreateUser(List list) {
log.info("批量创建用户入参:{}", JSON.toJSONString(list));
if (CollectionUtils.isEmpty(list)) {
log.error("入参集合不能为空");
throw new BizException("入参集合不能为空");
}
int size = 10;
long keepAliveTime = 60;
long start = System.currentTimeMillis();
BlockingQueue workQueue = new ArrayBlockingQueue<>(10000);
ThreadFactory threadFactory = new DefaultThreadFactory("executor");
ExecutorService executorService
= new ThreadPoolExecutor(size, size, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
List> futureList = new ArrayList<>();
for (UserDto userDto : list) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程名称:{}", Thread.currentThread());
try {
Long id = userManager.createUser(userDto);
TimeUnit.SECONDS.sleep(3L);
log.info("线程:{} id={} done", Thread.currentThread(), id);
return Boolean.TRUE;
} catch (InterruptedException e) {
log.error("创建用户异常:{}", e.getMessage(), e);
return Boolean.FALSE;
}
}, executorService);
futureList.add(future);
}
Boolean result = Boolean.TRUE;
try {
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).get(10, TimeUnit.SECONDS);
for (CompletableFuture future : futureList) {
Boolean back = future.get();
if (Boolean.FALSE.equals(back)) {
result = Boolean.FALSE;
}
}
} catch (Exception e) {
log.error("创建用户异常:{}", e.getMessage(), e);
result = Boolean.FALSE;
}
long end = System.currentTimeMillis();
log.info("批量创建用户耗时:{}", (end - start));
log.info("批量创建用户出参:{}", result);
return result;
}
}
package com.summer.toolkit.service;
import com.summer.toolkit.dto.UserDto;
import com.summer.toolkit.exception.BizException;
import com.summer.toolkit.mock.UserManager;
import com.summer.toolkit.mock.UserServiceImpl;
import com.summer.toolkit.util.FileUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
@ExtendWith(MockitoExtension.class)
@EnabledIfEnvironmentVariable(named = "DEBUG", matches = "true")
public class UserServiceTest {
@Mock
private Logger log;
@Mock
private UserManager userManager;
@InjectMocks
private UserServiceImpl userService;
@Test
public void testCreateUser() {
// 模拟依赖方法
Mockito.when(userManager.createUser(any())).thenReturn(Long.valueOf(1));
// 调用被测方法
UserDto userDto = this.buildUserDto();
Long result = userService.createUser(userDto);
// 验证方法结果
Long expect = 1L;
Assertions.assertEquals(expect, result);
// 验证方法是否被调用
Mockito.verify(userManager).createUser(userDto);
// 验证依赖对象只有这一个
Mockito.verifyNoMoreInteractions(userManager);
}
@Test
public void testUpdateUser() {
// 模拟依赖方法
Mockito.when(userManager.updateUser(any())).thenReturn(Boolean.TRUE);
Mockito.when(userManager.getUser(any())).thenReturn(new UserDto());
// 调用被测方法
UserDto userDto = this.buildUserDto();
userDto.setId(1L);
Boolean result = userService.updateUser(userDto);
// 验证方法结果
Assertions.assertEquals(Boolean.TRUE, result);
// 验证方法是否被调用
Mockito.verify(userManager).getUser(any());
Mockito.verify(userManager).updateUser(any());
}
@Test
public void testGetUser() {
// 模拟依赖方法
Mockito.when(userManager.getUser(any())).thenReturn(new UserDto());
// 调用被测方法
UserDto userDto = this.buildUserDto();
userDto.setId(1L);
UserDto result = userService.getUser(userDto);
// 验证方法结果
Assertions.assertNotNull(result);
// 验证方法是否被调用
Mockito.verify(userManager).getUser(userDto);
}
@Test
public void testBatchCreateUser() {
// 模拟依赖方法,指定单个异常类型
Mockito.when(userManager.createUser(any())).thenThrow(BizException.class);
// 调用被测方法
List param = new ArrayList<>();
UserDto userDto = this.buildUserDto();
param.add(userDto);
Boolean result = userService.batchCreateUser(param);
// 验证方法结果
Assertions.assertEquals(Boolean.FALSE, result);
// 验证方法是否被调用,默认一次
Mockito.verify(userManager).createUser(userDto);
// 验证方法是否被调用了1次
Mockito.verify(userManager, Mockito.times(1)).createUser(any());
}
@Test
public void testBatchCreateUserTimes() {
// 模拟依赖方法,指定单个异常类型
Mockito.when(userManager.createUser(any())).thenReturn(1L);
// 调用被测方法
List param = new ArrayList<>();
UserDto userDto = this.buildUserDto();
param.add(userDto);
param.add(userDto);
param.add(userDto);
Boolean result = userService.batchCreateUser(param);
// 验证方法结果
Assertions.assertEquals(Boolean.TRUE, result);
// 验证方法是否被调用了3次
Mockito.verify(userManager, Mockito.times(3)).createUser(any());
}
@Test
public void testFileUtils() {
// 构建对象
List list = new ArrayList<>();
list.add("1");
list.add("2");
// 模拟对应的类
// JDK11及以上版本中,try块中的变量可以在外部声明
MockedStatic mocked = Mockito.mockStatic(FileUtils.class);
try (mocked) {
// 模拟依赖静态方法
mocked.when(() -> FileUtils.readFileAllLines(anyString())).thenReturn(list);
// 调用被测方法
List lines = FileUtils.readFileAllLines(anyString());
// 验证方法结果
Assertions.assertEquals(list.size(), lines.size());
} catch (Exception e) {
log.error("模拟静态方法异常:{}", e.getMessage(), e);
}
}
/**
* 构建用户数据传输对象
*
* @return UserDto 返回构建好的用户数据传输对象
*/
private UserDto buildUserDto() {
UserDto userDto = new UserDto();
userDto.setUsername("小明");
userDto.setBirthday(new Date());
userDto.setAddress("北京市大兴区亦庄经济开发区");
userDto.setComment("加麻加辣");
userDto.setGender(1);
return userDto;
}
}