通俗学习Mockito结合Spring跨多层接口mock测试方法

1,984 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

通俗学习Mockito结合Spring跨多层接口mock测试方法

1、场景:A调B,B调C,测试A,mock掉C

调用链路示例代码:

  • ServiceA方法调用了ServiceB.getUserDto()方法
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
    
    public UserVo getUserVo(String id) {
        // 一堆处理
        UserDto userDto = serviceB.getUserDto(id);
        // 一堆处理
        return BeanUtils.copy(userDto, UserVo.class);
    }
}
  • ServiceB方法调用了ServiceC.getUser()方法
@Service
public class ServiceB {
    @Autowired
    private ServiceC serviceC;
    
    public UserDto getUserDto(String id) {
        // 一堆处理
        User user = serviceC.getUser(id);
        // 一堆处理
        return BeanUtils.copy(user, UserDto.class);
    }
}
  • 业务场景是mock掉ServiceC.getUser()方法
@Service
public class ServiceC {
    public User getUser(String id) {
        // 一堆处理
        return this.getById(id);
    }
}

2、Mock处理: 详细如代码,参照代码注释

  1. 把需要mock注入的服务ServiceA,ServiceB加上@InjectMocks
  2. 把需要mock的服务ServiceC加上@Mock@Spy
  3. 执行测试方法前@Before初始化Mock注入,加上MockitoAnnotations.initMocks(this);
  4. 调用测试接口前执行需要mock的方法,指定mock的返回值 when(serviceC.getUser(anyInt())).thenReturn(user);
//手动导入static的Mockito包
import static org.mockito.Mockito.*;

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring-config.xml")
public class MockTest {
    //需要mock注入的服务
    @InjectMocks
    @Autowired
    private ServiceA serviceA;
    //需要mock注入的服务
    @InjectMocks
    @Autowired
    private ServiceB serviceB;
    //需要mock掉的服务
    @Mock
    @Autowired
    private ServiceC serviceC;
    //初始化mock注入
    @Before
    public void initMock() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        //指定当调用ServiceC.getUser()时返回的user对象
        when(serviceC.getUser(anyInt())).thenReturn(user);
        /*
         * serviceA -> serviceB -> serviceC
         * 这里serviceA.getUserVo()里调用serviceB.getUserDto()方法,
         * serviceB里又调用serviceC.getUser()方法,mock掉serviceC的getUser()方法
         */
        UserVo userVo = serviceA.getUserVo("123");
        log.info(JSONObject.toJSONString(userVo)); // UserVo(1, "张三")
    }
}

3、扩展:

  1. @Mock@Spy的区别:

    • @Mock如果不写形如when(...).thenReturn(...)的打桩,服务下的所有属性方法将返回0或null;
    • @Spy不写when(...).thenReturn(...)打桩则是按真实的代码执行。
  2. when(...).thenReturn(...)doReturn(..).when(...)的区别:

    • 两者都返回mock结果,前者会调用真实代码后返回mock结果,后者直接返回mock结果。
    • 用法区别:when(serviceA.getUser(anyInt())).thenReturn(user)doReturn(user).when(serviceA).getUser(anyInt())