JAVA

Mockito @Mock 和 @MockBean

有些bean不想Mock,则必须要启动Spring容器,使用容器帮忙注入的Bean,需要进行Mock行为的类此时必须用MockBean注入。

在单元测试中,大多数都是用的Mock注入,因为Mock注入一般可以满足需求。但是一次测试中,应该属于集成测试,需要容器中相关的类,所以Mock注入不能满足要求,只能用MockBean注入。@mockBean注解将Mock对象添加到Spring上下文中。注解的对象将替换Spring上下文中任何相同类型的现有bean,如果没有定义相同类型的bean,将添加一个新的bean。

如果是简单的Mock,则配置非常简单,如下:

这里不需要借助任何容器。对于MockBean,是需要启动容器,配置如下:

上面是JUnit4的写法,JUnit5的更简单,只需要@SpringBootTest注解即可启动SpringBoot容器测试。

@SpringBootTest
public class OrderServiceTest {
   @Resource
   private OrderService orderService;
   @Test
   public void testInsert() {
      Order order = new Order();
      order.setOrderNo("A001");
      order.setUserId(100);
      orderService.insert(order);
   }
} 

通过SpringRunner.class,和@SpringBootTest,配置运行环境为test启动Spring容器。通过@Autowired注入测试类UnitTestMockBean。

这里重点:UnitTestMockBean是通过容器注入的,UnitTestRepository是通过MockBean注入的。

下面图片的UnitTestEntityCheckService这个类就是 本文主题,这个类不想Mock,这个类用的是容器的。

UnitTestMockBean是通过容器注入,同时也会注入UnitTestEntityCheckService,但是UnitTestRepository是通过MockBean注入的。

代码可以自己看 github地址:MockBean的使用

package pers.xue.skills.service;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
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.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import pers.xue.skills.entity.UnitTestEntity;
import pers.xue.skills.repository.UnitTestRepository;

import java.util.Arrays;
import java.util.List;

/**
 * 注意:
 * 1、Mock不需要依赖Spring环境,MockBean是需要Spring容器支持,但是配置环境可以启动test.yml
 * MockBean场景: 可以进行一些简单的大部分的测试,但是如果有些类你不能Mock时,需要用容器生成的类,比如本例子中的
 * UnitTestEntityCheckService,它是一个公共类,可以供很多地方使用,这个时候你需要借助容器中的它去实现,这个时候需要MockBean去Mock一些其它需要Mock的。
 * 2、@RunWith(MockitoJUnitRunner.class) 不能用这个,这个是Mock环境的,不会加载Spring环境
 * 3、启动Spring环境,可以用SpringBootTest、或者可以用Context
 * 4、用ActiveProfiles配置要用的配置类
 * 5、初步测试是MockBean能注入Mock之后的值,说明启动了Spring环境,或者可以通过控制台看到-The following profiles are active: test
 *
 * @author :HUANG ZHI XUE
 * @date :Create in 2022-06-09
 */

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class UnitTestMockBeanTest {

    @MockBean
    UnitTestRepository unitTestRepository;

    @Autowired
    UnitTestMockBean unitTestMockBean;

    @Test
    public void testGetEligibleUnitTestEntity() {
        List<UnitTestEntity> unitTestEntities = Arrays.asList(new UnitTestEntity(1, "content"));
        Mockito.when(unitTestRepository.findAll()).thenReturn(unitTestEntities);
        List<UnitTestEntity> eligibleUnitTestEntity = unitTestMockBean.getEligibleUnitTestEntity();
        Assert.assertEquals(unitTestEntities, eligibleUnitTestEntity);
    }
}

总结:
如果测试中不需要用到容器中的东西,即所有都可以Mock注入,那Mock够用了,大部分也够…
如果测试中需要用到一部分不想Mock的类,比如Mapper,公共判断等的这些类,则可以启动Spring容器,那些不想要Mock的直接不管,让容器注入,那些想Mock此时不能用注解@Mock,只能用@MockBean。
归纳差异:前者不需要容器,比较简单,后者需要启动容器。