You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails 2.2.2单元测试mock Calendar.getInstance()报错求助

当然可以Mock Calendar 类!你遇到的错误是因为mock的调用次数预期和实际调用不匹配,再加上代码里还有个小坑,咱们一步步来解决。

错误原因拆解

  1. 调用次数不匹配:你的测试代码里只声明了一次getInstance()的调用预期,但服务方法getMesesCrearMetrica()在循环中每次都会调用Calendar.getInstance(),当实际调用次数超过你定义的预期次数时,就会抛出No more calls to 'getInstance' expected at this point. End of demands.这个错误。
  2. 变量赋值错误:你写的def cal = Calendar.getInstance().set(Calendar.MONTH, 0)有问题——Calendar.set()方法返回的是void,所以cal实际是null,就算mock成功了,后续调用get(Calendar.MONTH)也会报空指针异常。

修正后的测试代码

首先修正cal的赋值,然后调整mock的调用预期,允许getInstance()被多次调用(用anyTimes()或者指定次数):

@TestFor(FechaService)
class FechaServiceTests {
    void testGetMesesCrearMetrica() {
        given:
        // 正确初始化Calendar实例,set方法是void,不能链式赋值
        def cal = Calendar.getInstance()
        cal.set(Calendar.MONTH, 0)
        
        def mockCalendar = mockFor(Calendar)
        // 允许getInstance被任意次数调用
        mockCalendar.demand.static.getInstance(anyTimes()) { cal }
        mockCalendar.createMock()

        when:
        def meses = service.getMesesCrearMetrica()

        then:
        // 这里可以添加你的断言,比如验证返回的meses符合预期
        meses.size() == 0 // 因为第一个循环就会break(月份匹配)
    }
}

额外优化建议(可选)

你的服务方法里每次循环都调用Calendar.getInstance()其实没必要,完全可以把实例获取放到循环外面,这样既提升性能,也让测试更简单:

def getMesesCrearMetrica(){
    def meses = [:]
    // 只获取一次Calendar实例
    def currentMonth = Calendar.getInstance().get(Calendar.MONTH)
    for(def mes : Meses.values()){
        if(mes.value -1 == currentMonth)
            break
        meses[mes.value] = mes.name()
    }
    return meses
}

这样修改后,测试里只需要声明一次getInstance()的调用预期就够了,也不会出现调用次数不匹配的问题。

内容的提问来源于stack exchange,提问作者Ernesto Vargas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:35:00