使用Mock进行业务逻辑层Service测试详解

 更新时间:2023年08月29日 11:35:52   作者:疯狂的帆  
这篇文章主要介绍了使用Mock进行业务逻辑层Service测试详解,mock是一种模拟对象的技术,用于在测试过程中替代真实的对象,通过mock,我们可以控制被模拟对象的行为和返回值,以便进行更加精确的测试,需要的朋友可以参考下

场景

公司采用的是分层开发,controller、Service、dao层分离,现在写dao层代码的人生病了,进度比较慢,现在你写的是 Service层的代码,怎么测试 Service 层代码是否正确呢?

Service层测试的重点是什么?

  • DAO层调用的次数
  • 以及调用的顺序
  • 并不关心最后数据是否准确

mock是什么?

在软件测试中,mock是一种模拟对象的技术,用于在测试过程中替代真实的对象。

通过mock,我们可以控制被模拟对象的行为和返回值,以便进行更加精确的测试。

测试代码示例

准备环境

引入依赖

<!-- Junit测试包 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
</dependency>
<!-- 专门用来做业务逻辑层 或者 Controller层的测试的 -->
<dependency>
    <groupId>org.easymock</groupId>
    <artifactId>easymock</artifactId>
    <version>3.5.1</version>
</dependency>

准备Dao层测试接口,不需要方法的实现

public interface AaDao {
    void a();
    void b();
}
public interface BbDao {
    void c();
    void d();
}

service 测试代码

public interface ABService {
    void aa();
    void bb();
    void cc();
    void dd();
}

testService 在此方法中使用 mock 进行测试

public class TestService {
    private ABService abService = new ABServiceImpl();
}

1. 简单测试 createMock

@Override
public void aa() {
    aDao.a();
}

测试代码

@Test
public void testAA() {
    // 创建对象
    AaDao aaDao = EasyMock.createStrictMock(AaDao.class);
    // 记录
    aaDao.a();
    EasyMock.expectLastCall();
    // 使能设置
    EasyMock.replay(aaDao);
    // 接下来调用Service进行测试
    abService.setaDao(aaDao);
    abService.aa();
    // 进行校验
    EasyMock.verify(aaDao);
}

2. 测试调用顺序 createStrictMock

@Override
public void ee() {
    aDao.b();
    aDao.a();
}

测试代码1

// 测试调用顺序
@Test
public void testEE1() {
    // 创建对象
    AaDao aaDao = EasyMock.createMock(AaDao.class);
    // 进行记录
    aaDao.a();
    EasyMock.expectLastCall();
    aaDao.b();
    EasyMock.expectLastCall();
    // 使能设置,保存记录信息
    EasyMock.replay(aaDao);
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.ee();
    // 进行校验
    EasyMock.verify(aaDao);
}

运行此代码,结果竟然是正确的,明明调用顺序不一致,却还是正确,这显然是不对的

测试代码2 使用createStrictMock

@Test
public void testEE2() {
    // 创建对象
    AaDao aaDao = EasyMock.createStrictMock(AaDao.class);
    // 进行记录
    aaDao.b();
    EasyMock.expectLastCall();
    aaDao.a();
    EasyMock.expectLastCall();
    // 使能设置,保存记录信息
    EasyMock.replay(aaDao);
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.ee();
    // 进行校验
    EasyMock.verify(aaDao);
}

3. 测试方法多次调用以及调用顺序

@Override
public void bb() {
    aDao.a();
    aDao.b();
    aDao.b();
    aDao.a();
}

测试代码

@Test
public void testBB() {
    // 创建对象
    AaDao aaDao = EasyMock.createStrictMock(AaDao.class);
    // 记录
    aaDao.a();
    EasyMock.expectLastCall();
    aaDao.b();
    EasyMock.expectLastCall();
    aaDao.b();
    EasyMock.expectLastCall();
    aaDao.a();
    EasyMock.expectLastCall();
    // 使能设置,即保存记录信息
    EasyMock.replay(aaDao);
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.bb();
    // 进行校验
    EasyMock.verify(aaDao);
}

如果是多次调用的话,就需要书写多次记录

4. 测试调用不同dao的方法

@Override
public void cc() {
    aDao.a();
    bDao.c();
}

测试代码1

@Test
public void testCC1() {
    // 创建对象
    AaDao aaDao = EasyMock.createStrictMock(AaDao.class);
    BbDao bbDao = EasyMock.createStrictMock(BbDao.class);
    // 进行记录
    bbDao.c();
    EasyMock.expectLastCall();
    aaDao.a();
    EasyMock.expectLastCall();
    // 使能设置,保存记录信息
    EasyMock.replay(aaDao, bbDao);
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.setbDao(bbDao);
    abService.cc();
    // 进行校验
    EasyMock.verify(aaDao, bbDao);
}

可以看出来,createStrictMock方法并不能保证多个 dao之间的调用顺序,只能对单个的DAO的调用顺序有严格的要求

测试代码2 createStrictControl

@Test
public void testCC2() {
    // 创建一个 controller,约束这些dao是一个整体
    IMocksControl control = EasyMock.createStrictControl();
    // 创建对象
    AaDao aaDao = control.createMock(AaDao.class);
    BbDao bbDao = control.createMock(BbDao.class);
    // 进行记录
    aaDao.a();
    EasyMock.expectLastCall();
    bbDao.c();
    EasyMock.expectLastCall();
    // 使能设置,保存记录信息
    control.replay();
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.setbDao(bbDao);
    abService.cc();
    // 进行校验
    control.verify();
}

使用 createStrictControl 定义一个整体,进行多个 dao 的测试

5. 测试不同dao调用顺序及次数

@Override
public void dd() {
    aDao.a();
    bDao.c();
    bDao.d();
    aDao.a();
}

测试代码

@Test
public void testDD() {
    // 创建一个 controller,约束这些dao是一个整体
    IMocksControl control = EasyMock.createStrictControl();
    // 创建对象
    AaDao aaDao = control.createMock(AaDao.class);
    BbDao bbDao = control.createMock(BbDao.class);
    // 进行记录
    aaDao.a();
    EasyMock.expectLastCall();
    bbDao.c();
    EasyMock.expectLastCall();
    bbDao.d();
    EasyMock.expectLastCall();
    aaDao.a();
    EasyMock.expectLastCall();
    // 使能设置,保存记录信息
    control.replay();
    // 调用 Service 测试
    abService.setaDao(aaDao);
    abService.setbDao(bbDao);
    abService.dd();
    // 进行校验
    control.verify();
}

测试此方法时,即便是调换 同一个dao的方法也会报错,满足条件

总结

测试 service 层时,可以使用 mock 框架进行测试,引入 mock依赖即可,操作简单

如果测试的 service 只包含一个dao,那么使用 EasyMock.createStrictMock() 即可进行测试

如果测试的 service 包含多个dao,那么使用 EasyMock.createStrictControl(); 创建一个 control 进行包裹即可测试

到此这篇关于使用Mock进行业务逻辑层Service测试详解的文章就介绍到这了,更多相关Mock测试Service内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java8 统计字符串字母个数的几种方法总结(推荐)

    java8 统计字符串字母个数的几种方法总结(推荐)

    下面小编就为大家分享一篇java8 统计字符串字母个数的几种方法总结(推荐),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来吧
    2017-11-11
  • Spring Boot使用yml格式进行配置的方法

    Spring Boot使用yml格式进行配置的方法

    很多springboot项目使用的是yml格式,主要目的是方便对读懂其他人的项目,下面小编通过本文给大家分享Spring Boot使用yml格式进行配置的方法,需要的朋友参考下吧
    2018-04-04
  • Java技能点之SimpleDateFormat进行日期格式化问题

    Java技能点之SimpleDateFormat进行日期格式化问题

    这篇文章主要介绍了Java技能点之SimpleDateFormat进行日期格式化问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 解读@Transactional失效的几种情况

    解读@Transactional失效的几种情况

    这篇文章主要介绍了@Transactional失效的几种情况,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Java设计模式之装饰模式详解

    Java设计模式之装饰模式详解

    这篇文章主要介绍了Java设计模式中的装饰者模式,装饰者模式即Decorator Pattern,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,装饰模式又名包装模式。装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案
    2022-07-07
  • 使用java.util.Timer实现任务调度

    使用java.util.Timer实现任务调度

    这篇文章主要为大家详细介绍了使用java.util.Timer实现任务调度,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • java8、jdk8日期转化成字符串详解

    java8、jdk8日期转化成字符串详解

    在本篇文章中小编给大家整理了关于java8、jdk8日期转化成字符串的相关知识点和代码,需要的朋友们学习下。
    2019-04-04
  • java AOP原理以及实例用法总结

    java AOP原理以及实例用法总结

    在本篇文章里我们给大家整理了关于java AOP原理以及相关知识点总结,正在学习的朋友们参考下。
    2019-05-05
  • springmvc+Hibernate+JPA(混合事务)解读

    springmvc+Hibernate+JPA(混合事务)解读

    在Spring项目中,Spring Data JPA作为一种持久层框架,因其简化数据库操作而受到青睐,但在将其引入使用Hibernate的旧项目时,可能会遇到事务处理问题,解决方案包括配置两种事务管理器:Hibernate事务管理器和JPA事务管理器
    2024-09-09
  • 如何解决HttpServletRequest.getInputStream()多次读取问题

    如何解决HttpServletRequest.getInputStream()多次读取问题

    这篇文章主要介绍了如何解决HttpServletRequest.getInputStream()多次读取问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07

最新评论