如何在类方法中对File类进行Spock Spy?测试内有效类内无效
解决Spock测试中业务类内部new File的Spy问题
我来帮你搞定这个Spock测试的问题!你遇到的核心问题是:业务类Clazz里是直接在方法内部new File对象,这种局部实例化的操作,普通的Mock或者非全局Spy根本拦不住。得用Groovy的全局Spy来劫持File的构造逻辑,才能让业务类里new出来的File变成我们的Mock实例。
先给你修正后的正确测试代码
class ClazzSpec extends Specification { def "调用fun方法时,文件存在则不抛出异常"() { given: // 全局Spy File类,因为File是final类,必须加useObjenesis绕过构造限制 GroovySpy(File, global: true, useObjenesis: true) // 创建Mock的File实例,指定exists()返回true def mockFile = Mock(File) { exists() >> true } // 拦截所有带String参数的File构造调用,返回我们的mock实例 new File(_ as String) >> mockFile when: // 注意!业务类的fun是实例方法,必须先new Clazz再调用 new Clazz().fun("test.file") then: // 验证没有抛出异常 noExceptionThrown() // 还可以验证exists方法确实被调用了一次 1 * mockFile.exists() } def "调用fun方法时,文件不存在则抛出异常"() { given: GroovySpy(File, global: true, useObjenesis: true) def mockFile = Mock(File) { exists() >> false } new File(_ as String) >> mockFile when: new Clazz().fun("test.file") then: // 验证抛出指定异常 thrown(FileNotFoundException) 1 * mockFile.exists() } }
关键注意点(也是你原来代码的问题)
- 业务类方法调用错误:你原来测试里写的
Clazz.fun("test.file")是错的!因为fun是实例方法,必须先实例化Clazz对象再调用。 - 全局Spy的配置:必须给
GroovySpy加上global: true,这样才能拦截到业务类内部new出来的File,而不是只拦截测试代码里的。另外File是final类,得加useObjenesis: true让Groovy能创建代理实例。 - 构造方法拦截:要用
new File(_ as String)来匹配所有String参数的File构造调用,确保不管业务类传什么路径,都返回我们的Mock实例。你原来的new File(path) >> {mockFile}可能因为path变量的问题没匹配上,用通配符_更稳妥。
这样调整后,业务类里new出来的File就会被替换成我们的Mock实例,测试就能正常验证逻辑啦!
内容的提问来源于stack exchange,提问作者Kfir
相关产品推荐
相关产品推荐

