首页 > 其他分享 >对时间强依赖的方法如何做单元测试

对时间强依赖的方法如何做单元测试

时间:2024-02-07 16:22:19浏览次数:26  
标签:DateUtil 00 依赖 单元测试 parse Date new 方法

背景

项目当中需要进行业务时间的校验,如上午 9:00-下午 17:00,在 9:00 前或 17:00 后是不能处理相关业务的。因此在业务校验的 Service 中定义了一个 checkBizTime() 方法。原本代码如下:

public void checkBizTime() {
    Date currentTime = new Date();
    // DateUtil.parse的作用是将配置文件中读取的时间字符串转换为Date对象,
    // bizStartTimeStr、bizEndTimeStr 是从配置文件中读取的变量,用 @Value 注解注入
    Date bizStartTime = DateUtil.parse(bizStartTimeStr, "HH:mm:ss");
    Date bizEndTime = DateUtil.parse(bizEndTimeStr, "HH:mm:ss");
    if (currentTime.before(bizStartTime) || currentTime.after(bizEndTime)) {
        throw new BizException("不在业务时间范围内,无法处理业务");
    }
}

但是如何对这个方法进行单元测试,成了一个很头疼的问题。我们知道,单元测试具有独立性和可重复性,但如果要测试上面这段方法,就会发现当系统时间在 9:00 ~ 17:00 内时,这个方法可以通过测试,而不在这个时间范围内,这个方法就会抛出异常,也就是说,这个测试方法依赖于当前系统时间,且不同时间运行测试,得到的测试结果是不同的!这违反了单元测试的独立性和可重复性。因此我们必须让时间固定在某个特定的时间。

解决方法

解决方法:在 DateUtil 类中建立一个 getCurrentDate() 方法,这个方法返回 new Date() 对象。(如果 DateUtil 是第三方库的,或是其他人开发的,那么就在项目中自己定义一个,当然名字需要和 DateUtil 区分开)

public static Date getCurrentDate() {
    return new Date();
}

然后把上述业务代码中的 new Date() 部分替换成 DateUtil.getCurrentDate()

public void checkBizTime() {
    Date currentTime = DateUtil.getCurrentDate();
    // DateUtil.parse的作用是将配置文件中读取的时间字符串转换为Date对象,
    // bizStartTimeStr、bizEndTimeStr 是从配置文件中读取的变量,用 @Value 注解注入
    Date bizStartTime = DateUtil.parse(bizStartTimeStr, "HH:mm:ss");
    Date bizEndTime = DateUtil.parse(bizEndTimeStr, "HH:mm:ss");
    if (currentTime.before(bizStartTime) || currentTime.after(bizEndTime)) {
        throw new BizException("不在业务时间范围内,无法处理业务");
    }
}

然后编写单元测试,注意要先引入 mockito-inline 这个包,才可以对静态方法进行 Mock。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <scope>test</scope>
</dependency>

单元测试代码如下:

class BizCheckServiceTest {
    @InjectMocks
    private BizCheckServiceImpl bizCheckServiceUnderTest;

    @Mock
    private MockedStatic<DateUtil> mockedDateUtil;

    @BeforeEach
    void setup() {
        openMocks(this);
        mockedDateUtil
            .when(DateUtil::getCurrentDate)
            .thenReturn(new Date(2024, 2, 3, 10, 0, 0));
        // 假设固定返回 2024年2月3日 10:00:00。但此构造函数已弃用,可以使用其他方式返回Date对象
        // 对 DateUtil 类中的其他方法,可以让他执行真实方法
        mockedDateUtil
            .when(() -> DateUtil.parse(anyString(), anyString()))
            .thenCallRealMethod();
    }

    @Test
    void testCheckBizTime() {
        bizCheckServiceUnderTest.checkBizTime();
        // 验证 getCurrentTime() 方法被执行1次,
        // parse() 方法被执行2次
        verify(mockedDateUtil, times(1)).getCurrentTime();
        verify(mockedDateUtil, times(2)).parse(anyString(), anyString());
    }

    @AfterEach
    void tearDown() {
        // 每次使用完 MockedStatic 接口需要关闭,不然会导致测试方法报错
        mockedDateUtil.close();
    }
}

这样就可以重复执行该单元测试,每次执行的结果应该都是一样的。保持了单元测试的独立性和可重复性。

标签:DateUtil,00,依赖,单元测试,parse,Date,new,方法
From: https://www.cnblogs.com/ryuasuka/p/18011027

相关文章

  • useEffect 传入的函数,它的返回值要么是一个方法(清理函数),要么就是undefined,其他情况都
    useEffect传入的函数,它的返回值要么是一个方法(清理函数),要么就是undefined,其他情况都会报错比较常见的一个情况是,我们的useEffect需要执行一个async函数,比如://❌//Type'Promise<void>'providesnomatch//forthesignature'():void|undefined'useEffect(asyn......
  • 后台没有调用分页方法,但是sql的执行却走了分页
    1、分页方法主要调用PageHelper.startPage()现象:开始是可以查询所有数据,在我调整前台代码以后,SQl查询就变为分页的了。因此,肯定是vue代码有问题,具体为啥前台代码会影响后台的分页呢?很是神奇。(计算机问题,表面上都有神秘的面纱哈哈哈)做法:(1)比对请求参数,发现比原来多了分页参数pa......
  • AI大模型的使用-让AI帮你写单元测试
    随着人工智能技术的不断发展,AI大模型在许多领域都展现出了强大的能力。其中一个令人兴奋的应用领域是软件开发,尤其是单元测试的编写和执行。通过利用AI大模型的生成能力和自然语言处理技术,我们可以自动化地编写和执行单元测试,从而提高测试效率和代码质量。一、AI大模型在单元测试中......
  • Java获取方法的调用者
    publicstaticvoidmain(String[]args){method1();}staticvoidmethod1(){method2();}staticvoidmethod2(){method3();}staticvoidmethod3(){printCallingInfo();}staticvoidp......
  • kubernetes集群故障排查的几种方法
    1.kubectldescribe查看资源的详细信息,根据事件信息获取当前资源的状态,从而给出解决方案。[root@master231pod]#kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEimage-resources-stress-040/1Pending02m13s[root@mas......
  • JUnit实践教程——Java的单元测试框架
    前言大家好,我是chowley,最近在学单元测试框架——JUnit,写个博客记录一下!在软件开发中,单元测试是确保代码质量和稳定性的重要手段之一。JUnit作为Java领域最流行的单元测试框架,为开发人员提供了简单、灵活和强大的测试工具。JUnit1.简介JUnit是一个开源的Java单元测试框架,最初由......
  • C# 泛型方法New泛型对象
     var frm=Activator.CreateInstance<T>(); ///<summary>//////</summary>///<typeparamname="T"></typeparam>///<paramname="pnlFrm"></param>///......
  • 【多线程例题】使用三个线程,分别可以打印A,B,C。要求实现三个线程协同打印,顺序打印出ABC
    顺序打印-进阶版方法一:三个线程竞争同一个锁,通过count判断是否打印三个线程分别打印A,B,C方法一:通过count计数打印(三个线程上同样的锁,打印一个,召唤所有锁,如果不满足条件,则wait等待,锁自动解锁)方法二:/***有三个线程,分别只能打印A,B和C*要求按顺序打印ABC,打印10次*输出示......
  • Python中的包模块引用成员的方法
    在Python中,包(package)和模块(module)是组织和管理代码的重要方式。将代码分成不同的模块或包可以更好地组织代码结构,使代码更易于维护和管理。说的通俗点,就是将代码整理成一块一块,然后使用时候相互拼接完成就可以使用,这样的好处是可用性高而且非常方便维护,尤其是在选择大型爬虫项目的......
  • Python实例:一个类调用另一个类的方法
    在Python面向对象编程中,类与类之间可以相互交互和调用。本文将介绍如何在一个类中调用另一个类的方法,以实现代码的模块化和复用。一、类与对象简介在Python中,类是一种自定义数据类型,用于封装数据和功能。对象是类的实例,可以通过类创建多个对象。类定义了对象的属性和方法,可以在对象......