@Mock @MockBean @InjectMocks之间的关系
首先说@mock 和 @MockBean
具体的介绍大家可以看
Mockito的@Mock与@MockBean
一言以蔽之就是
@Mock可以生产一个空的类,这个类的方法体都是空的,方法的返回值(如果有的话)都是null。
@MockBean可以生产一个空的类,并且用这个类替代spring容器中同类型的类。
而@InjectMocks就是产生一个空的类,这个类里面的字段用这个测试类里面被@Mock的字段填充。
@SpringBootTest
public class MockitoTest {
@MockBean
private MyService myService;
@InjectMocks
private UserController userController;
@Test
public void testGet(){
Person person = new Person();
person.setName("张三");
Long id = 15L;
when(personMapper.selectById(id)).thenReturn(person);
when(myService.say()).thenReturn("by mock");
Person result = userController.getUserById(id);
}
我写了上面的测试代码,发现不论怎么运行,userController里面的MyService 字段都是null,感觉就是userController里面MyService 字段上面的autowired没有起作用。
我一直在调整代码,发现了如下的情况
-
前提条件
ClassB里面有个ClassA,classa被标注了Autowired -
case1
测试类上只有 @ExtendWith(MockitoExtension.class) 的情况下 测试类里被 @MockBean 标注的字段就是空的 -
case2
测试类上只有 @ExtendWith(SpringExtension.class)的情况下
测试类里被 @MockBean 标注的字段(假定为ClassA)不是空的
但是被 @InjectMocks标注的类(假定为ClassB)
ClassB里面标注了Autowired的ClassA依然是null -
case3
@SpringBootTest 里面本身就包含着 @ExtendWith(SpringExtension.class)
如果测试类上只有 @SpringBootTest 测试类里被 @MockBean 标注的字段(假定为ClassA)不是空的
但是被 @InjectMocks标注的类(假定为ClassB)
ClassB里面标注了Autowired的ClassA依然是null -
case4
如果测试类上只有 @ExtendWith(MockitoExtension.class)
测试类里被 @Mock标注的字段不是null,也能正常的注入被 @InjectMocks标注的类 -
case5
如果测试类上只有 @SpringBootTest
虽然测试类里classB被标注了 @InjectMocks
但是classB里面的classA依然是null 即使代码里面的ClassA类上标注了 @Component
看到我头都大了。
我的目标就是把 @MockBean标注的类注入到@InjectMocks里面。但是一直不行。
最终我把@InjectMocks改成了@autowired 发现可以注入了
但是被标注了@autowired里面缺不能注入被标注了@mock的字段!
最终得到一个结论
被@InjectMocks标注的字段,只能被注入被@mock标注的类(@mockbean标注的不行)
被@autowired标注的字段,只能被注入被@mockbean标注的类(@mock标注的不行)
再简而言之就是
要想把需要打桩的类注入到我们要测试的类里面,有下面两个思路
- @ExtendWith(MockitoExtension.class) + @InjectMocks +@Mock
- @SpringBootTest +@Autowired+@MockBean
两个的区别在于- 是否启动了SpringBoot。(当然这个区别没有现实意义,因为我写代码做测试的目的是验证模块功能的正确性,是否启动Spirngboot只是手段不是目的)
- 启动SpringBoot方便做集成测试,使用ExtendWith(MockitoExtension.class)方便做模块内简单的单元测试。(至于这两种测试的区别,google上的说明有很多,不过我同时的认为前者测试的范围更广,粒度也更大,依赖的模块更多,依赖也要求是真实实现的)