• Mockito的@Mock与@MockBean


    在上文的
    https://blog.csdn.net/dlf123321/article/details/127930378 里 大家初步会用mockito了
    但是马上出现了一个问题。

    package com.example.demo.controller;
    
    
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.example.demo.entity.Person;
    import com.example.demo.mapper.PersonMapper;
    import lombok.AllArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    import java.util.Random;
    
    @RequestMapping({"/user"})
    @RestController
    @Slf4j
    @AllArgsConstructor
    public class UserController {
    
        @Autowired
        private RedissonClient redisson;
    
        @Autowired
        private PersonMapper personMapper;
    
    
        @RequestMapping("/getUserById")
        public Person getUserById(Long id){
            Person person =personMapper.selectById(id);
            if ("张三".equals(person.getName())){
                return person;
            }
            if ("李四".equals(person.getName())){
                person.setAge(17);
                return person;
            }
            return person;
        }
    }
    
    
    • 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

    相比较于上一篇文章,UserController 里面多了一个RedissonClient 。这东西是干啥的?不用太纠结,就把它当一个分布式锁的实现就ok。
    那它怎么初始化呢?

    package com.example.demo.conf;
    
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.Config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.io.IOException;
    
    @Configuration
    @Slf4j
    public class MyRedissonConfig {
    
    
        @Autowired
        RedisProperties redisProperties;
    
        /**
         * 对 Redisson 的使用都是通过 RedissonClient 对象
         * @return
         * @throws IOException
         */
        @Bean(destroyMethod="shutdown") // 服务停止后调用 shutdown 方法。
           public RedissonClient redisson() throws IOException {
            // 1.创建配置
            Config config = new Config();
            // 集群模式
            // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
            // 2.根据 Config 创建出 RedissonClient 示例。
            String address = "redis://"+redisProperties.getHost()+":"+redisProperties.getPort();
            config.useSingleServer().setAddress(address).setPassword(redisProperties.getPassword());
            return Redisson.create(config);
        }
    }
    
    
    • 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

    按照上一篇的MockitoTest运行,就会报错因为redis的host连接失败(因为我之前申请的redis已经过期了)所以不能生成RedissonClient ,然后UserController 就失败了。
    可是我现在就是想测试UserController 了呀,我并不关注RedissonClient 呀。
    怎么办,我想到了一个我可以排除RedissonClient 呀。
    我给MyRedissonConfig 的redisson()方法加上@ConditionalOnMissingBean(name = “org.springframework.boot.test.mock.mockito.MockitoPostProcessor”)
    如果启动的是Mockioto那就不要初始化RedissonClient 了。
    这个方法太棒了。
    但是又报错了
    No qualifying bean of type ‘org.redisson.api.RedissonClient’…
    因为spring容器里没有RedissonClient就不能实例化UserController。哦好像有点道理呀。那我改一下MockitoTest如下:

    @SpringBootTest
    @ExtendWith(MockitoExtension.class)
    public class MockitoTest {
        @Mock
        private PersonMapper personMapper;
    
        @Mock
        private RedissonClient redissonClient;
    
        @InjectMocks
        private  UserController userController;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    还是不行。报错和上面一样,也是No qualifying bean of type ‘org.redisson.api.RedissonClient’…

    网上找了一圈之后发现,有个@MockBean
    然后我再改代码
    @MockBean
    private RedissonClient redissonClient;
    改成这样就ok。
    ok 上面说了那么多,终于到正题了,那就是 @MockBean和@Mock到底有什么区别。
    我所理解的区别就是@Mock生成的类和spring容器没有关系,虽然在上文PersonMapper 他也注入进了UserController 。
    但是@MockBean生成的类会进入Spring容器?
    怎么证明?
    看代码

    package com.example.demo.controller;
    
    import com.example.demo.entity.Person;
    import com.example.demo.mapper.PersonMapper;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.context.ApplicationContext;
    
    import static org.mockito.Mockito.when;
    
    @SpringBootTest
    public class MockitoTest {
        @Mock
        private PersonMapper personMapper;
    
        @MockBean
        private RedissonClient redisson;
    
        @InjectMocks
        private  UserController userController;
    
        @Autowired
        private ApplicationContext context;
    
        @Test
        public void testGet(){
            PersonMapper mapperFromSpring = context.getBean(PersonMapper.class);
            Assertions.assertNotEquals(mapperFromSpring,personMapper);
            Assertions.assertEquals(personMapper,userController.getPersonMapper());
            Assertions.assertNotEquals(mapperFromSpring,userController.getPersonMapper());
    
            RedissonClient clientFromSpring = context.getBean(RedissonClient.class);
            Assertions.assertEquals(clientFromSpring,redisson);
            Assertions.assertEquals(userController.getRedisson(),redisson);
            
            Person person = new Person();
            person.setName("张三");
            Long id = 15L;
            when(personMapper.selectById(id)).thenReturn(person);
            Person result = userController.getUserById(id);
            Assertions.assertEquals(person,result);
    
        }
    }
    
    • 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

    在这里插入图片描述


    以下是之后的补充,多看了一些文档之后,发现我自己没有理清楚SpringBoot与Mockito的关系,按照最开始的需求
    我直接写下面的代码就ok了。

    package com.example.demo.controller;
    
    import com.example.demo.entity.Person;
    import com.example.demo.mapper.PersonMapper;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.redisson.api.RedissonClient;
    import org.springframework.context.ApplicationContext;
    
    import static org.mockito.Mockito.when;
    
    @ExtendWith(MockitoExtension.class)
    public class MockitoTest {
        @Mock
        private PersonMapper personMapper;
        @Mock
        private RedissonClient redisson;
        @InjectMocks
        private  UserController userController;
    
    
        @Test
        public void testGet(){
            Assertions.assertEquals(personMapper,userController.getPersonMapper());
            Assertions.assertEquals(userController.getRedisson(),redisson);
    
            Person person = new Person();
            person.setName("张三");
            Long id = 15L;
            when(personMapper.selectById(id)).thenReturn(person);
            Person result = userController.getUserById(id);
            Assertions.assertEquals(person,result);
    
        }
    }
    
    • 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

    另外多说一点
    @InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。

    @Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。

    @Spy:对函数的调用均执行真正部分。
    我们最应该经常使用的是InjectMocks与Spy。

  • 相关阅读:
    【FastCAE源码阅读7】视图方向切换按钮实现原理
    吃透Chisel语言.20.Chisel组合电路(二)——Chisel编码器与解码器实现
    深入分析高性能互连点对点通信开销
    【数据结构】——排序算法的相关习题
    具名挂载和匿名挂载
    【思科交换机命令大全,含巡检命令,网工建议收藏!】
    java aspose cells 读取名称管理器
    读写分离MySQL
    迎战阿里诸神,庚顿喜提智能制造全球总决赛第三名
    想持续“遥遥领先”,中国需要自己的光刻胶
  • 原文地址:https://blog.csdn.net/dlf123321/article/details/127931154