本文对应源码:欢迎关注我的公众号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多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。