SpringBoot + Mockito单元测试

前言

为了保证代码质量,在写完代码后,写单测是很有必要的。当然,在大部分情况下,我们可能不会写单测,而是直接把应用部署起来,直接自测,然后再联调。估计很大一部分人,都是用这种方式开发。当然,我之前也是按这个方式来开发,单测覆盖率纯粹是为了满足公司的指标要求,大部分流于形式。

写单测好处

慢慢的,我感受到写单测带来的几个好处:

1、提升效率

启动一个应用,几分钟,找bug,修bug,再重启应用。这个过程不断的重复,应用重启太浪费时间。而单测不需要重启整个应用,只对几个service做测试,效率高很多

2、场景覆盖全

单测可以对代码运行中的各种情况进行模拟,并对最终的返回结果断言,这是自己自测很难模拟的。而且,这些单测,是沉淀的资产。下次修改代码,可以重跑以前单测,发现问题,避免踩坑。

单测怎么写

我们很容易对单测产生误解,所以这里我先把2个概念说明一下:

1、集成测试

测试过程中,会启动整个Spring容器,调用DB 或者  依赖的外部接口等。只不过访问的环境是测试环境。这个过程最大程度还原生产环境过程,但是耗时长。

2、单元测试

不启动整个应用,只对单个接口/类进行测试。不调用DB 、外部接口,依赖的服务都Mock掉,只测试代码逻辑。这个过程,测试用例耗时短。

我们说的单测,是指第2种。

单测过程分2步,第一步:Mock外部依赖,第二步:断言

Mockito

Mock框架很多,我以比较熟悉的Mockito为例,介绍单测的基本过程

            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>3.3.3</version>
                <scope>test</scope>
            </dependency>
@Service
public class ServiceA{
    @Resource
    private DaoA daoA;

    @Resource
    private ServiceC serviceC;

    
}

注入Mock service

1、全部Mock
@Mock
private ServiceA serviceA;

这种方式,serviceA中的所有方法都会被mock,并不会真正被调用到

2、依赖注入

ServiceA 依赖了 ServiceC 和 DaoA,使用InjectMocks可以自动注入

@InjectMocks
private ServiceA serviceA;
3、真实调用
@Spy
private ServiceC serviceC;

这种方式,调用serviceC的方法,会被真实调用

Mock非静态有返回结果方法

doNothing().when(serviceA).save(any(AbnormalTask.class));

Mock非静态无返回结果方法

Mockito.when(serviceA.getItem(any(AAA.class))).thenAnswer(invocationOnMock -> {
    
    return xxx;
});

Mock静态方法

try (MockedStatic<IdGenerator> utilities = Mockito.mockStatic(IdGenerator.class)) {
    utilities.when(() -> IdGenerator.generate(null)).thenReturn("1");
    FulfillSingleResult<Object> fulfillSingleResult = serviceA.executeTask(taskExecuteRequest);
    assertTrue(fulfillSingleResult.isSuccess());
}

需要注意的是,断言的内容需要写到try{} 代码块内部,否则会不生效。

断言返回结果

assertTrue(fulfillSingleResult.isSuccess());
assertFalse(xxx);

断言异常

@Rule
public ExpectedException thrown = ExpectedException.none();
thrown.expectMessage("xxx异常");

完整例子



@RunWith(MockitoJUnitRunner.class)
public class ServiceATest {

    @Mock
    private DaoA daoA;

    @Mock
    private ServiceC serviceC;

    @InjectMocks
    private ServiceA serviceA;


    @Test
    public void testGetItem() throws Exception {

        Mockito.when(daoA.getItem(any(AAA.class))).thenAnswer(invocationOnMock -> {
            return xxx;
        });

        assertTrue(serviceA.getItem() != null);

    }
}

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值