单测篇(mockito)-一文彻底搞懂@Spy和@Mock的区别

本文原标题《单测篇(mockito)-当@Autowired注解了List或Map对象时,如何写单测》

本文对应源码:欢迎关注我的公众号nrsc,并在同名文章中获取本文对应源码。

@Spy和@Mock到底有什么区别?相信读完本文,你一定会真真切切地明白。

1 先明确一下具体问题

假设有下面这样一个技术方案:

该方案对应的伪代码如下,那该如何对下面的方法进行写单测呢?

@Autowired
private List<CompensateJudge> compensateJudgeList;

public Object calculateCompensateAmount(Object object) {
    //判断是否满足赔付条件,
    //如果有不满足的赔付条件,拿到不满足的具体详情
    List<CompensateJudgeDetail> failureDetails =
            compensateJudgeList.stream()
                    //判断是否要赔付
                    .map(j -> j.judge(object))
                    //过滤出不满足赔付的详情
                    .filter(r -> !r.isLegal())
                    .collect(Collectors.toList());
    
    if (!CollectionUtils.isEmpty(failureDetails)) {
        log.info("该广告主本周期内无需赔付,并记录无需赔付的具体原因");
        return "无需赔付";
    }

    log.info("该广告主本周期内需要赔付,并计算赔付金额;");
    return "需赔付,已计算赔付金额";
}

2 使用@Mock

这里直接给出使用@Mock写的单测代码:

public class AccountCompensateBizServiceTest {

    @Mock
    CompensateJudge compensateJudge;
    @Mock //使用@Mock创建的是一个完全模拟对象,它的任何方法都不会被真正调用,
    // 都需要模拟,本方案就需要对compensateJudgeList的stream()进行模拟
    List<CompensateJudge> compensateJudgeList;
    @Mock
    Logger log;
    @InjectMocks
    AccountCompensateBizService accountCompensateBizService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCalculateCompensateAmount001() throws Exception {
        CompensateJudgeDetail detail = new CompensateJudgeDetail();
        detail.setLegal(true);
        detail.setReason(null);
        //模拟compensateJudge的judge方法
        when(compensateJudge.judge(any())).thenReturn(detail);
        //模拟compensateJudgeList的stream()方法
        //【注意!!!】伪代码是用lambda表达式写的,如果用的for循环,这里可就不好mock了
        when(compensateJudgeList.stream()).thenReturn(Stream.of(compensateJudge));
        Object res = accountCompensateBizService.calculateCompensateAmount("object");
        Assert.assertEquals(res.toString(), "需赔付,已计算赔付金额");
    }

    @Test
    public void testCalculateCompensateAmount002() throws Exception {
        CompensateJudgeDetail detail = new CompensateJudgeDetail();
        detail.setLegal(false);
        detail.setReason("XXX");
        //模拟compensateJudge的judge方法
        when(compensateJudge.judge(any())).thenReturn(detail);
        //模拟compensateJudgeList的stream()方法,
        //【注意!!!】伪代码是用lambda表达式写的,如果用的for循环,这里可就不好mock了
        when(compensateJudgeList.stream()).thenReturn(Stream.of(compensateJudge));
        Object res = accountCompensateBizService.calculateCompensateAmount("object");
        Assert.assertEquals(res.toString(), "无需赔付");
    }
}

【注意!!!】伪代码是用lambda表达式写的,如果用的for循环,这里可就不好mock了。

3 使用@Spy

当@Mock不好用的情况下,我们还可以使用@Spy,这里也直接给出使用@Spy写的单测代码:

public class AccountCompensateBizServiceTest2 {

    @Mock
    CompensateJudge compensateJudge;
    @Spy
    //使用@Spy创建的对象,其方法会执行真实逻辑,
    // 因此也可以调用List对象的add方法为其add元素
    // 但@Mock却不行(任何方法都不会被真正调用,都需要模拟)
    List<CompensateJudge> compensateJudgeList = new ArrayList<>();
    @Mock
    Logger log;
    @InjectMocks
    AccountCompensateBizService accountCompensateBizService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

    }

    @Test
    public void testCalculateCompensateAmount001() throws Exception {
        CompensateJudgeDetail detail = new CompensateJudgeDetail();
        detail.setLegal(true);
        detail.setReason(null);
        when(compensateJudge.judge(any())).thenReturn(detail);
        //为compensateJudgeList添加一个mock的对象
        compensateJudgeList.add(compensateJudge);
        Object res = accountCompensateBizService.calculateCompensateAmount("object");
        Assert.assertEquals(res.toString(), "需赔付,已计算赔付金额");
    }

    @Test
    public void testCalculateCompensateAmount() throws Exception {
        CompensateJudgeDetail detail = new CompensateJudgeDetail();
        detail.setLegal(false);
        detail.setReason("XXX");
        when(compensateJudge.judge(any())).thenReturn(detail);
        //为compensateJudgeList添加一个mock的对象
        compensateJudgeList.add(compensateJudge);
        Object res = accountCompensateBizService.calculateCompensateAmount("object");
        Assert.assertEquals(res.toString(), "无需赔付");
    }
}

贴一下单测覆盖率

文章至此,想必你对@Mock和@Spy肯定有了更加深刻的认识。

4 留给读者

  • 当@Autowired注解了Map对象时如何写单测???

读完上面的文章想必对你来说肯定是小case了,所以这个问题留给读者!😁😁😁

本文由mdnice多平台发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nrsc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值