当前位置:   article > 正文

SpringBoot使用junit5+mockito单元测试(不连接中间件)_junit测试 不操作数据库

junit测试 不操作数据库

不启动web容器

springboot版本2.5.4,主要解决在不连接数据库、redis等中间件的情况下进行测试,同时包含mock文件、jedis连接池、成员变量、接口的具体方法

1. 引入jar包

  • 这里使用gradle,不是maven,使用了redis,mybatis-plus
//redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'redis.clients:jedis'

//mybatis-plus
implementation group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.4.3.1'

//test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//mock redis客户端时使用
implementation 'ai.grakn:redis-mock:0.1.6'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. 被测试类

  • 只为演示单元测试的具体实现,这里省略被测试类之外的其他类的代码
package com.example.handlerinterceptor.sysuser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.handlerinterceptor.sysuser.dao.SysUserDao;
import com.example.handlerinterceptor.sysuser.entity.SysUser;
import com.example.handlerinterceptor.sysuser.service.SysUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Value("${fileType}")
    private Set<String> fileType;

    @Resource
    private SysUserDao sysUserDao;

    @Resource
    private JedisConnectionFactory jedisConnectionFactory;

    @Override
    public List<SysUser> getSysUsers(String roleName) {
        // 为了演示mock成员变量,无实际意义
        System.out.println(fileType);
        // 为了演示mock jedis连接池,无实际意义
        Jedis jedis = (Jedis)jedisConnectionFactory.getConnection().getNativeConnection();
        Set<String> keys = jedis.keys("*");
        System.out.println(keys);
        // 为了演示解决mybatis-plus的can not find lambda cache for this entity错误处理方式
        LambdaQueryWrapper<SysUser> queryWrapper =
            new LambdaQueryWrapper<SysUser>().eq(SysUser::getRole, roleName).orderByAsc(SysUser::getUserId);
        List<SysUser> sysUsers = sysUserDao.selectList(queryWrapper);
        return sysUsers;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

3. 测试类

  • 如果不需要连接中间件,需要使用注解@ExtendWith(MockitoExtension.class),这样就可以mock所有的方法返回值,而不需要直接请求数据库或者第三方接口
package com.example.handlerinterceptor.sysuser.service.impl;

import ai.grakn.redismock.RedisServer;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.example.handlerinterceptor.sysuser.dao.SysUserDao;
import com.example.handlerinterceptor.sysuser.entity.SysUser;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.mock.web.MockMultipartFile;
import redis.clients.jedis.Jedis;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;

@ExtendWith(MockitoExtension.class)
class SysUserServiceImplTest {

    @InjectMocks
    private SysUserServiceImpl sysUserService;

    @Mock
    private SysUserDao sysUserDao;

    @Mock
    private JedisConnectionFactory jedisConnectionFactory;

    /**
     * mock redis客户端
     * https://dzone.com/articles/java-redis-mock
     */
    private static RedisServer redisServer = null;

    @BeforeAll
    public static void init() throws IOException {
        redisServer = RedisServer.newRedisServer(6379);
        redisServer.start();
    }

    @AfterAll
    public static void close() {
        if (redisServer != null) {
            redisServer.stop();
        }
    }

    /**
     * 解决mybatis-plus错误:can not find lambda cache for this entity [com.example.handlerinterceptor.sysuser.entity.SysUser]
     * https://github.com/baomidou/mybatis-plus/issues/2569
     */
    @BeforeAll
    static void initiated() {
        TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "SysUser"), SysUser.class);
    }

    /**
     * {@link SysUserServiceImpl#getSysUsers(String)}
     */
    @Test
    void getSysUsers() {
        // mock 接口类,这里没使用
        HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
        HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
        //mock jedis
        Mockito.doReturn(new JedisConnection(mockJedis())).when(this.jedisConnectionFactory).getConnection();
        //mock 成员变量
        mockField(sysUserService, "fileType", Set.of("jpg", "png", "heic"));
        //设置参数
        String roleName = "vip";
        SysUser sysUser = new SysUser();
        sysUser.setUserId(123L);
        //mock 方法返回值
        Mockito.doReturn(List.of(sysUser)).when(this.sysUserDao)
            .selectList(ArgumentMatchers.any(LambdaQueryWrapper.class));
        //执行方法
        List<SysUser> sysUsers = sysUserService.getSysUsers(roleName);
        System.out.println(sysUsers);
        //断言执行结果
        Assertions.assertNotNull(sysUsers);
        // 没有返回值的方法可以使用verify
        Mockito.verify(sysUserDao, Mockito.times(1)).selectList(ArgumentMatchers.any(LambdaQueryWrapper.class));

    }

    /**
     * mock 文件上传
     */
    private MockMultipartFile mockMultipartFile(String fileName, String contentType) {
        byte[] content = new byte[2];
        content[0] = 1;
        content[1] = 2;
        MockMultipartFile mockMultipartFile = new MockMultipartFile("file", fileName, contentType, content);
        return mockMultipartFile;
    }

    /**
     * mock 成员变量
     */
    private void mockField(Object target, String fieldName, Object value) {
        // jdk 反射
        try {
            Field field = target.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(target, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // spring 反射
        // ReflectionTestUtils.setField(target, fieldName, value);
    }

    /**
     * mock jedis
     */
    private Jedis mockJedis() {
        Jedis jedis = new Jedis(redisServer.getHost(), redisServer.getBindPort());
        jedis.set("redis-a", "123");
        jedis.set("redis-b", "456");
        jedis.set("redis-c", "789");
        return jedis;
    }

    /**
     * mock FeignException Request request = Request.create("GET", "", new HashMap<>(), null, null);
     * Mockito.doThrow(FeignException.NotFound.errorStatus("", Response.builder().status(404).request(request).build()))
     */

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

在这里插入图片描述

需要启动web容器进行接口测试的方式

  • controller接口类
package com.example.handlerinterceptor.sysuser.controller;

import com.example.handlerinterceptor.dto.AjaxResult;
import com.example.handlerinterceptor.sysuser.entity.SysUser;
import com.example.handlerinterceptor.sysuser.service.SysUserService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("sysUser")
public class SysUserController {
    /**
     * 服务对象
     */
    @Resource
    private SysUserService sysUserService;

    @PostMapping("/getSysUsers")
    public AjaxResult<List<SysUser>> getSysUsers(@RequestBody SysUser sysUser) {
        List<SysUser> sysUsers = sysUserService.getSysUsers(sysUser.getRole());
        return AjaxResult.ok(sysUsers);
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

1. 方式一,MockMvc

package com.example.handlerinterceptor.sysuser.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.handlerinterceptor.sysuser.entity.SysUser;
import com.example.handlerinterceptor.sysuser.service.SysUserService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import javax.annotation.Resource;
import java.util.List;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@AutoConfigureMockMvc
@SpringBootTest
class SysUserControllerTest {

    private static final String GET_SYS_USERS = "/sysUser/getSysUsers";

    @Resource
    private MockMvc mockMvc;

    /**
     * 需要被mock返回结果的bean,用来替代spring容器中真正的bean;如果不需要mock数据,可以不使用这个bean
     */
    @MockBean
    private SysUserService sysUserService;

    /**
     * {@link SysUserController#getSysUsers(SysUser)}
     */
    @Test
    void getSysUsers() throws Exception {
        String userRole = "{\"role\":\"vip\"}";
        SysUser sysUser = new SysUser();
        sysUser.setUserId(123L);
        Mockito.when(sysUserService.getSysUsers(ArgumentMatchers.anyString())).thenReturn(List.of(sysUser));
        MvcResult mvcResult = mockMvc
            .perform(MockMvcRequestBuilders.request(HttpMethod.POST, GET_SYS_USERS)
                .contentType(MediaType.APPLICATION_JSON).content(userRole))
            .andExpect(status().isOk()).andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("Success"))
            .andDo(print()).andReturn();
        String contentAsString = mvcResult.getResponse().getContentAsString();
        System.out.println(contentAsString);
        JSONObject jsonObject = JSONObject.parseObject(contentAsString);
        Assertions.assertEquals(jsonObject.get("code"), 0);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 对sysUserService mock数据后的打印

在这里插入图片描述

  • 没有对sysUserService mock数据后的打印,打印数据库中的真实数据

在这里插入图片描述

2. 方式二,直接注入接口类

package com.example.handlerinterceptor.sysuser.controller;

import com.example.handlerinterceptor.dto.AjaxResult;
import com.example.handlerinterceptor.sysuser.entity.SysUser;
import com.example.handlerinterceptor.sysuser.service.SysUserService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
class SysUserControllerTest3 {

    @Resource
    private SysUserController sysUserController;

    @MockBean
    private SysUserService sysUserService;

    /**
     * {@link SysUserController#getSysUsers(SysUser)}
     */
    @Test
    void getSysUsers() {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(123L);
        sysUser.setRole("vip");
        Mockito.when(sysUserService.getSysUsers(ArgumentMatchers.anyString())).thenReturn(List.of(sysUser));

        AjaxResult<List<SysUser>> sysUsers = sysUserController.getSysUsers(sysUser);
        System.out.println(sysUsers);
        Assertions.assertEquals(sysUsers.getCode(), 0);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

在这里插入图片描述

mock同类中的其他方法

  • 比如需要在getUserName方法中mock saveUser方法的返回值

@Service
public class SysUserServiceImpl implements SysUserService {

    @Override
    public List<String> getUserName(String role) {
        Boolean aBoolean = this.saveUser("Fisher3652");
        if (aBoolean) {
            return List.of("Fisher3652");
        }
        return null;
    }

    @Override
    public Boolean saveUser(String name) {
        return true;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 单元测试类
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

@ExtendWith(MockitoExtension.class)
class SysUserServiceImplTest {

    @InjectMocks
    private SysUserServiceImpl sysUserService;

    /**
     * {@link SysUserServiceImpl#getUserName(String)}
     */
    @Test
    void getUserName() {
        SysUserServiceImpl spy = Mockito.spy(sysUserService);
        Mockito.doReturn(Boolean.TRUE).doReturn(Boolean.FALSE).when(spy).saveUser(ArgumentMatchers.anyString());
        List<String> userName = spy.getUserName("123");
        Assertions.assertNotNull(userName);
        List<String> userName2 = spy.getUserName("456");
        Assertions.assertNull(userName2);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号