Grails 2.2.2单元测试mock Calendar.getInstance()报错求助
当然可以Mock Calendar 类!你遇到的错误是因为mock的调用次数预期和实际调用不匹配,再加上代码里还有个小坑,咱们一步步来解决。
错误原因拆解
- 调用次数不匹配:你的测试代码里只声明了一次
getInstance()的调用预期,但服务方法getMesesCrearMetrica()在循环中每次都会调用Calendar.getInstance(),当实际调用次数超过你定义的预期次数时,就会抛出No more calls to 'getInstance' expected at this point. End of demands.这个错误。 - 变量赋值错误:你写的
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
相关产品推荐
相关产品推荐

