在上文的
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。