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

相比较于上一篇文章,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);
    }
}

按照上一篇的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;

还是不行。报错和上面一样,也是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);

    }
}

在这里插入图片描述


以下是之后的补充,多看了一些文档之后,发现我自己没有理清楚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);

    }
}

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

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

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

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值