Mockito:模拟测试框架的具体介绍与使用

Posted ABin-阿斌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mockito:模拟测试框架的具体介绍与使用相关的知识,希望对你有一定的参考价值。

我是 ABin-阿斌:写一生代码,创一世佳话,筑一揽芳华。 如果小伙伴们觉得我的文章不错,记得一键三连哦。
在这里插入图片描述

一、什么是Mockito

Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象,进而简化有外部依赖的类的测试。

二、有什么作用:

提前创建测试,TDD(测试驱动开发)

  • 如果你创建了一个 Mock 那么你就可以在 service 接口创建之前写 Service Tests 了,这样你就能在开发过程中把测试添加到你的自动化测试环境中了。换句话说,模拟使你能够使用测试驱动开发。

团队可以并行工作

  • 这类似于上面的那点;为不存在的代码创建测试。但前面讲的是开发人员编写测试程序,这里说的是测试团队来创建。当还没有任何东西要测的时候测试团队如何来创建测试呢?模拟并针对模拟测试!
  • 这意味着当 service 接口需要测试时,实际上 QA 团队已经有了一套完整的测试组件;没有出现一个团队等待另一个团队完成的情况。这使得模拟的效益型尤为突出了。

你可以创建一个验证或者演示程序。

  • 由于Mocks 非常高效,Mocks 可以用来创建一个概念证明,作为一个示意图,或者作为一个你正考虑构建项目的演示程序。这为你决定项目接下来是否要进行提供了有力的基础,但最重要的还是提供了实际的设计决策。

隔离系统

  • 有时,你希望在没有系统其他部分的影响下测试系统单独的一部分。由于其他系统部分会给测试数据造成干扰,影响根据数据收集得到的测试结论。使用 mock 你可以移除掉除了需要测试部分的系统依赖的模拟。
  • 当隔离这些 mocks 后,mocks 就变得非常简单可靠,快速可预见。这为你提供了一个移除了随机行为,有重复模式并且可以监控特殊系统的测试环境。

三、具体如何使用:

  • 在使用 Mockito 测试框架时,我们需要提前在 idea 中装一个测试插件,这个插件会帮我们生成大部分的测试代码,从而减少我们的一个测试开发成本。

IntelliJ idea 需要安装的测试插件

在这里插入图片描述
当我们安装好这个插件后我们只需要选中我们想要测试的类——操作如下:

在这里插入图片描述
这里可以根据你们公司所规定的测试版本来,我这里用的是 JUnit5 和 Mockito

在这里插入图片描述

经过以上操作后,我们 ServiceImpl 中有几个方法,这个插件就会帮我们生成几个相对应的测试方法,当然这里我们还需要自己手动改一下

  • init()和 最下面那个方法是通用的,其方法根据自己的实际情况来测试就可以了。下面看不懂的注解可以去查一下主要是 Junit5 和 Mockito测试框架

3.1 Mockito的API介绍

3.2案例解析:

要测试的 DtMachineIncomeServiceImpl 实现类

@Service
public class DtMachineIncomeServiceImpl extends ServiceImpl<DtMachineIncomeMapper, DtMachineIncomeEntity> implements DtMachineIncomeService {

    @Autowired
    private DtMachineAddressIncomeDayService dtMachineAddressIncomeDayService;
    @Autowired
    private DtMachineInfoService dtMachineInfoService;

    @Override
    public BigDecimal profitByTeamsAndCurrency(List<Long> teamIds, String currencyMark) {
        DynamicTableParser.setId(currencyMark);
        List<DtMachineIncomeEntity> machineIncomeEntityList = this.list(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .in(DtMachineIncomeEntity::getOrganizationId, teamIds));
        return machineIncomeEntityList.parallelStream().map(DtMachineIncomeEntity::getActualTotalIncome).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    @Override
    public DtMachineIncomeEntity getOneByOrganizationIdAndMachineId(Long organizationId, Long machineIdId) {
        return this.getOne(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .eq(DtMachineIncomeEntity::getOrganizationId, organizationId)
                .eq(DtMachineIncomeEntity::getMachineId, machineIdId)
                .last(MybatisPlusConst.LIMIT_1));
    }


    @Override
    public boolean saveDtMachineIncome(DtMachineIncomeEntity entity) {
        return this.save(entity);
    }

    @Override
    public boolean updateByDtMachineIncomeId(DtMachineIncomeEntity entity) {
        return this.updateById(entity);
    }

    @Override
    public List<DtMachineIncomeEntity> listByTeamId(Long teamId) {
        return this.list(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .eq(DtMachineIncomeEntity::getOrganizationId, teamId));
    }

    @Override
    public DtMachineIncomeEntity lastTimeByTeamIds(List<Long> teamIdsByUserId) {
        return this.getOne(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .in(DtMachineIncomeEntity::getOrganizationId, teamIdsByUserId)
                .orderByDesc(DtMachineIncomeEntity::getUpdateTime)
                .last(MybatisPlusConst.LIMIT_1));
    }

    @Override
    public void updateMachineProfits(Long organizationId, Long machineIdd, DateTime dateTime, Integer type) {
        DynamicTableParser.setId(CurrencyMarkEnum.ETH.getMark());
        DtMachineIncomeEntity machineIncomeEntity = this.getOne(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .eq(DtMachineIncomeEntity::getMachineId, machineIdd)
                .eq(DtMachineIncomeEntity::getOrganizationId, organizationId));
        if (ObjectUtil.isEmpty(machineIncomeEntity)) {
            return;
        }
        DtMachineAddressIncomeDayEntity dtMachineAddressIncomeDayEntity = dtMachineAddressIncomeDayService.getOne(Wrappers.lambdaQuery(DtMachineAddressIncomeDayEntity.class)
                .eq(DtMachineAddressIncomeDayEntity::getOrganizationId, organizationId)
                .eq(DtMachineAddressIncomeDayEntity::getMachineId, machineIdd)
                .between(DtMachineAddressIncomeDayEntity::getDayTime, DateUtil.beginOfDay(dateTime), DateUtil.endOfDay(dateTime)));

        // 1-移动至  2-删除
        if (type == 1) {
            machineIncomeEntity.setTheoryIncome(BigDecimal.ZERO);
            if (ObjectUtil.isNotEmpty(dtMachineAddressIncomeDayEntity)) {
                dtMachineAddressIncomeDayEntity.setTheoryIncome(BigDecimal.ZERO);
                dtMachineAddressIncomeDayEntity.setUpdateTime(dateTime);
                dtMachineAddressIncomeDayService.updateById(dtMachineAddressIncomeDayEntity);
            }
        }
        machineIncomeEntity.setActualComputingPower("0");
        machineIncomeEntity.setTwentyFourAvgComputingPower("0");
        machineIncomeEntity.setUpdateTime(dateTime);
        this.updateById(machineIncomeEntity);
    }

    @Override
    public List<DtMachineIncomeEntity> listByTeamIdNoRepeat(Long teamId) {
        List<DtMachineIncomeEntity> returnList = new ArrayList<>();
        List<DtMachineInfoEntity> machineInfoList = dtMachineInfoService.listByTeamId(teamId);
        Map<Long, Long> count = machineInfoList.parallelStream().map(x -> x.getAddressId())
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        List<DtMachineInfoEntity> noRepeatAddressIds = new ArrayList<>();
        count.forEach((k, v) -> {
            if (ObjectUtil.isNotEmpty(k)) {
                DtMachineInfoEntity dtMachineInfoEntity = dtMachineInfoService.listByTeamIdAndAddressId(teamId, k);
                noRepeatAddressIds.add(dtMachineInfoEntity);
            }
        });
        if (ObjectUtil.isNotEmpty(noRepeatAddressIds)) {
            for (DtMachineInfoEntity infoEntity : noRepeatAddressIds) {
                DtMachineIncomeEntity oneByOrganizationIdAndMachineId = this.getOneByOrganizationIdAndMachineId(infoEntity.getOrganizationId(), infoEntity.getId());
                if (ObjectUtil.isNotEmpty(oneByOrganizationIdAndMachineId)) {
                    returnList.add(oneByOrganizationIdAndMachineId);
                }
            }
        }
        return returnList;
    }

    @Override
    public List<DtMachineIncomeEntity> listByTeamIds(List<Long> teamIds) {
        return this.list(Wrappers.lambdaQuery(DtMachineIncomeEntity.class)
                .in(DtMachineIncomeEntity::getOrganizationId, teamIds));
    }
}

测试类:下面的代码结合上面实现代码看会好懂一点

@ExtendWith({SpringExtension.class, ExtentUtils.class})
class DtMachineIncomeServiceImplTest {
	//除了我们测试类本身要真实的其它都可以进行 mock 模拟
    @MockBean
    DtMachineAddressIncomeDayService dtMachineAddressIncomeDayService;
    @MockBean
    DtMachineInfoService dtMachineInfoService;
    @MockBean
    DtMachineIncomeMapper dtMachineIncomeMapper;
    //这个必须要真实的,因为这个是我们要测试的主体类
    @Autowired
    DtMachineIncomeServiceImpl dtMachineIncomeServiceImpl;

    @BeforeAll
    public static void init() {
        TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), DtMachineIncomeEntity.class);
    }

    @Test
    @DisplayName("根据组织id集合,币种返回实际总收益")
    void testProfitByTeamsAndCurrency() {
        BigDecimal result = dtMachineIncomeServiceImpl.profitByTeamsAndCurrency(Arrays.<Long>asList(Long.valueOf(1)), "currencyMark");
        Assertions.assertEquals(new BigDecimal(0), result);
    }

    @Test
    @DisplayName("根据矿机id,组织id返回一天记录")
    void testGetOneByOrganizationIdAndMachineId() {
    	//模拟当第一次当用这个方法时,返回这个:new DtMachineIncomeEntity()
    	//any():表示所有、任何
        when(dtMachineIncomeServiceImpl.getOne(any())).thenReturn(new DtMachineIncomeEntity());
        DtMachineIncomeEntity result = dtMachineIncomeServiceImpl.getOneByOrganizationIdAndMachineId(Long.valueOf(1), Long.valueOf(1));
        //判断是否相等
        Assertions.assertEquals(new DtMachineIncomeEntity(), result);
    }
    
	@Test
    @DisplayName("保存对象")
    void testSaveDtMachineIncome() {
    	//模拟调用方法,返回 1
        when(dtMachineIncomeMapper.insert(any())).thenReturn(1);
        boolean result = dtMachineIncomeServiceImpl.saveDtMachineIncome(new DtMachineIncomeEntity());
        Assertions.assertEquals(true, result);
    }

    @Test
    @DisplayName("根据id修改")
    void testUpdateByDtMachineIncomeId() {
        when(dtMachineIncomeMapper.updateById(any())).thenReturn(1);
        boolean result = dtMachineIncomeServiceImpl.updateByDtMachineIncomeId(new DtMachineIncomeEntity());
        Assertions.assertEquals(true, result);
    }

    @Test
    @DisplayName("根据小组集合返回列表")
    void testListByTeamId() {
        when(dtMachineIncomeServiceImpl.list(any())).thenReturn(Arrays.<DtMachineIncomeEntity>asList(new DtMachineIncomeEntity()));
        List<DtMachineIncomeEntity> result = dtMachineIncomeServiceImpl.listByTeamId(Long.valueOf(1));
        Assertions.assertEquals(Arrays.<DtMachineIncomeEntity>asList(new DtMachineIncomeEntity()), result);
    }

    @Test
    @DisplayName("返回最新更新时间")
    void testLastTimeByTeamIds() {
        when(dtMachineIncomeServiceImpl.getOne(any())).thenReturn(new DtMachineIncomeEntity());
        DtMachineIncomeEntity result = dtMachineIncomeServiceImpl.lastTimeByTeamIds(Arrays.<Long>asList(Long.valueOf(1)));
        Assertions.assertEquals(new DtMachineIncomeEntity(), result);
    }

    @Test
    @DisplayName("ETH删除(移动至)矿机收益算力操作")
    void testUpdateMachineProfits() {
        dtMachineIncomeServiceImpl.updateMachineProfits(Long.valueOf(1), Long.valueOf(1), null, Integer.valueOf(0));
    }

    @Test
    @DisplayName("根据小组集合返回列表")
    void testListByTeamIdNoRepeat() {
        DtMachineInfoEntity mock = JMockData.mock(DtMachineInfoEntity.class);
        List<DtMachineInfoEntity> dtMachineInfos = new ArrayList<>();
        dtMachineInfos.add(mock);
        when(dtMachineInfoService.listByTeamId(any())).thenReturn(dtMachineInfos);
        when(dtMachineInfoService.listByTeamIdAndAddressId(any(), any())).thenReturn(mock);
        DtMachineIncomeEntity mock1 = JMockData.mock(DtMachineIncomeEntity.class);
        when(dtMachineIncomeServiceImpl.getOne(any())).thenReturn(mock1);
        List<DtMachineIncomeEntity> result = dtMachineIncomeServiceImpl.listByTeamIdNoRepeat(Long.valueOf(1));
        Assertions.assertEquals(Arrays.<DtMachineIncomeEntity>asList(mock1), result);
    }

    @Test
    @DisplayName("根据组织ID列表查询在矿机收益中是否存在数据")
    void testListByTeamIds() {
        when(dtMachineIncomeServiceImpl.list(any())).thenReturn(Arrays.<DtMachineIncomeEntity>asList(new DtMachineIncomeEntity()));
        List<DtMachineIncomeEntity> result = dtMachineIncomeServiceImpl.listByTeamIds(Arrays以上是关于Mockito:模拟测试框架的具体介绍与使用的主要内容,如果未能解决你的问题,请参考以下文章

你一定要知道的Mockito-Java开发的绝佳模拟框架

如何使用 Mockito 框架模拟我的服务

SpringBoot 单元测试利器——Mockito

Mockito与PowerMock的使用基础教程

Mock测试框架(Mockito为例)

使用强大的 Mockito 测试框架来测试你的代码