JUNIT5+Mockito单元测试

文章目录

  • 1、前言
  • 2、Maven依赖
    • 2.1 JDK21+SpringBoot版本基于3.1.0
    • 2.2 JDK17+SpringBoot版本基于2.2.5.RELEASE
  • 3、业务代码
  • 4、单元测试

1、前言

之前写过一篇使用testMe自动生成单元测试用例,使用的是junit4来编写的单元测试用例,目前很多新项目都已经使用JDK11+以及SpringBoot3+。本次基于junit5+Mockito来编写单元测试。

2、Maven依赖

2.1 JDK21+SpringBoot版本基于3.1.0

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
        

2.2 JDK17+SpringBoot版本基于2.2.5.RELEASE

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
        

3、业务代码

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;
    }

}

4、单元测试

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;
    }

}


你可能感兴趣的:(Java,单元测试,单元测试)