美文网首页程序员
优雅单测-3用Mockito轻松解决复杂的依赖问题

优雅单测-3用Mockito轻松解决复杂的依赖问题

作者: uncle_hangzhou | 来源:发表于2020-06-30 15:27 被阅读0次

    1.Mockito

    Mockito是GitHub上用于Java使用最广泛的Mock框架

    Mockito核心解决的问题:不管是测试驱动开发,还是系统架构本身,都会带来的依赖结构复杂问题;单元测试做软件中的最小可测试单元,只应依当前单元的配置。 所有较大的系统都会有依赖复杂的问题。 此类问题就需要Mock框架来解决

    2.快速上手

    使用很简单一般分3部:

    1. 模拟外部依赖注入容器

    2. 执行单测

    3. 验证单测逻辑

    2.1 SpringBoot环境

    2.1.1 依赖配置

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>${springboot.version}</version>
    </dependency>
    

    2.1.2 单测用例

    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = LiveReportServiceTest.Config.class)
    public class LiveReportServiceTest {
        @Autowired
        ILiveReportWriteService iLiveReportWriteService;
        @MockBean
        LiveReportMapper liveReportMapper;
    
        @Test
        public void updateLiveStatusTest() {
            int num = iLiveReportWriteService.updateById(1L);
            Assert.assertTrue(num >= 0);
        }
    
        @Configuration
        static class Config {
            @Bean
            ILiveReportWriteService iLiveReportWriteService() {
                return new LiveReportWriteServiceImpl();
            }
        }
    }
    

    @MockBean,在SpringBoot中通过@MockBean注解,就可以快速装在一个Mock的Bean了。

    此方式通过非常简单的方式解决了系统层级之间单测的依赖,可以用在数据层和业务层,也可以用在业务层之间的多项依赖等依赖上的问题

    直接执行:

    image.png

    2.1.3 复杂单测用例

    可以看到如果使用了SpringBoot,并且使用@MockBean可以快速解决依赖的问题。但是,Mock出的LiveReportMapper对象其实是个空壳,那么既然是mock就要知道如何通过mock的方式解决各种复杂逻辑

    下面模拟2种复杂逻辑,Service层的单元测试mock依赖的另外一个Service类"InfoService" ,并且mock里面的2个方法

    • 方法queryByLiveNo,任何调用都返回特定mock对象
    • 方法removeById,任何调用都mock异常情况出现

    下面看例子:

    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = LiveReportServiceTest.Config.class)
    public class LiveReportServiceTest {
        @Autowired
        ILiveReportWriteService iLiveReportWriteService;
     
        @Test
        public void updateLiveStatusTest() {
            int num = iLiveReportWriteService.updateById(1L);
            Assert.assertTrue(num >= 0);
        }
        
        @Test(expected = Exception.class)
        public void updateLiveStatusTest() {
            iLiveReportWriteService.remove(1L);
        }
    
        @Configuration
        static class Config {
            @Bean
            ILiveReportWriteService iLiveReportWriteService() {
                return new LiveReportWriteServiceImpl();
            }
            
            @Bean
            InfoService getLiveInfoService() throws LiveException {
                LiveInfoPO liveInfoPO = new LiveInfoPO(111L);
                liveInfoPO.setTime(System.currentTimeMillis());
                InfoService mock = Mockito.mock(InfoService.class);
                
                Mockito.when(mock.queryLiveInfoByLiveNo(Mockito.anyString())).thenReturn(liveInfoPO);
                Mockito.when(mock.removeById(Mockito.anyString())).thenThrow(new Exception());
                return mock;
            }
        }
    }
    
    • 假设iLiveReportWriteService.remove方法内部依赖了InfoService.removeById, 那么执行iLiveReportWriteService.remove方法时就会跑出异常

    • 假设iLiveReportWriteService.updateById方法内部依赖了InfoService.queryLiveInfoByLiveNo,那么执行InfoService.queryLiveInfoByLiveNo方法时就会返回111的id

    2.2 非SpringBoot环境

    如果没有SpringBoot环境的Starter,可以直接使用Mockito。 除了@MockBean不能使用其他功能不受影响,参考上面例子

    2.2.1 依赖配置

    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
    </dependency>
    

    更多用法参考Mockito官方文档,此处不做赘述

    官网地址:https://site.mockito.org/

    相关文章

      网友评论

        本文标题:优雅单测-3用Mockito轻松解决复杂的依赖问题

        本文链接:https://www.haomeiwen.com/subject/uksxqktx.html