SpringBoot JUnit 5 中关于@Spy、@Mock和@InjectMocks注解的使用总结
@Spy和@Mock的区别:@Spy修饰的属性里面的方法可以按照真实情况执行,在需要的时候可以打桩模拟执行结果,使用方式是Mockito.doReturn().when()--全都执行,有需要在改。@Mock修饰的属性都是null,在执行单元测试的时候每个方法都需要打桩模拟执行结果,使用方式是Mockito.when().thenReturn()--全部不执行,避免意外。 <p><
·
SpringBoot JUnit 5 中关于@Spy、@Mock和@InjectMocks注解的使用总结
/** * 单元测试旨在与其他组件隔离地测试组件,并且单元测试也有一个要求:执行时间要尽可能快,因为这些测试每天可能在开发人员计算机上执行数十次。 * <p> * @Spy和@Mock单元测试执行的速度快,需要打桩的代码多----写着麻烦,执行爽(随时都能执行) * @SpyBean和@MockBean单元测试执行的速度慢,需要打桩的代码少----写着省事,执行恶心(跑次单元测试就可以去吃饭了) * <p> * @Spy和@Mock的区别: * @Spy修饰的属性里面的方法可以按照真实情况执行,在需要的时候可以打桩模拟执行结果,使用方式是Mockito.doReturn().when()--全都执行,有需要在改。 * @Mock修饰的属性都是null,在执行单元测试的时候每个方法都需要打桩模拟执行结果,使用方式是Mockito.when().thenReturn()--全部不执行,避免意外。 <p> * <p> * <p> * @Spy和@InjectMocks 的应用场景: * @Spy修饰的属性在通过Mockito打桩数据时,无法将要打桩的属性自动注入。 * @InjectMocks则可以自动注入,另外@InjectMocks修饰的必须是完整的类。 例如: * UserServiceImpl属性如果用@Spy修饰,则在使用Mockito打桩模拟数据时,在UserServiceImpl中的userRepository属性直接就是null。 * UserServiceImpl属性如果用@InjectMocks修饰,则在使用Mockito打桩模拟数据时,在UserServiceImpl中的userRepository属性自动注入的是mock生成的代理对象。<p> * <p> * <p> * @Spy、@Mock和@InjectMocks修饰属性类型: <p> * 抽象类需要特殊处理(userCheckStrategy = Mockito.mock ( UserCheckStrategy.class, Answers.CALLS_REAL_METHODS);)。 * @Spy:可以自动注入到其他实现类的属性中。修饰接口不会报错,不过因为接口没有实现逻辑,所以不打桩模拟的时候,接口方法永远返回null。 * @Mock:可以自动注入到其他实现类的属性中。用@Mock修饰的属性不做打桩模拟返回结果的情况,返回的都是null,所以无所谓修饰的属性是不是接口。 * @InjectMocks:不可以自动注入到其他实现类的属性中。修饰接口会报错。 <p> * <p> * <p> * @Mock和@MockBean的直观区别: <p> * @SpyBean和@MockBean会启动Spring容器(即使指定了其他启动方式),并且替换Spring对应类型的bean,能够调用真实的网络请求 * @Spy和@Mock生成的对象不受spring管理,也不会替换Spring对应类型的bean * * <p> * <p> * 解决线程导致单元测试无法覆盖执行 * // 新增对异步线程里面Runnable方法的驱动 * Mockito.doAnswer( * (InvocationOnMock invocation) -> { * ((Runnable) invocation.getArguments()[0]).run(); * return null; * } * ).when(threadPoolTaskExecutor).execute(Mockito.any(Runnable.class)); * // 新增对异步线程里面Runnable方法的驱动 * Mockito.doAnswer( * (InvocationOnMock invocation) -> { * ((Runnable) invocation.getArguments()[0]).run(); * return null; * } * ).when(asyncExecutor).execute(Mockito.any(Runnable.class)); * <p> * 使用建议: * 1、默认使用@Spy,有需要打桩模拟返回结果的情况可以自定义模拟返回结果,尽可能的覆盖更多的代码逻辑。 * 2、对依赖项全部使用@Mock,每个依赖项都打桩模拟返回结果,有遗漏的地方会报空指针异常,在测试用例的开发阶段就能识别出来,尽可能的减少依赖项对单元测试执行结果的影响。 * 3、对于实现类中包含需要通过Mockito打桩模拟结果的依赖项属性时,使用@InjectMocks,使被@Mock修饰的属性能够自动注入到实现类中。 * 4、@Spy修饰实现类、@InjectMocks修饰实现类、@Mock修饰接口。 * <p> * <p> * 疑问: * Q:在OrderAggServiceImpl中的orderService属性如果没有手动set方式赋值的时候,orderService属性是null。 * 而其他属性threadPoolTaskExecutor、resourceService、snowflakeIdWorker都是自动有值不为空的。区别是orderService是@InjectMocks修饰, * 而其他有值的属性是@Spy修饰,但是将orderService属性用@Spy和@InjectMocks同时修饰也不能自动赋值,另外这两个注解同时使用时只有离属性最近的一个注解起作用。 * A: * <p> * Q:@Spy、@Mock和@InjectMocks三个注解的注入规则是什么?什么时候能自动注入,什么时候需要手动赋值? * A: * <p> * */
更多推荐
已为社区贡献2条内容
所有评论(0)