代码草图看起来像:
class MyClass { def cons MyClass() { cons = System.console() } def getInput = { prompt,defValue -> def input = (cons.readLine(prompt).trim()?:defValue)?.toString() def inputTest = input?.toLowerCase() input } }
我希望单元测试能够测试是否可以返回一些模拟响应,并且可以返回默认值.注意:这是简化的,所以我可以弄清楚如何进行单元测试,getInput方法中还有更多的代码需要测试,但是一旦我清除了这个障碍应该没问题.
由akhikhl编辑的每回答@H_502_18@根据建议,我做了一个简单的界面:
interface TestConsole { String readLine(String fmt,Object ... args) String readLine() char[] readPassword(String fmt,Object ... args) char[] readPassword() }
然后我尝试了这样的测试:
def "Verify get input method mocking works"() { def consoleMock = GroovyMock(TestConsole) 1 * consoleMock.readLine(_) >> 'validResponse' inputMethods = new MyClass() inputMethods.cons = consoleMock when: def testResult = inputMethods.getInput('testPrompt','testDefaultValue') then: testResult == 'validResponse' }
我选择不改变构造函数,因为我不想改变我的实际代码只是为了测试它.幸运的是,Groovy让我用一个’def’定义控制台,所以我做的工作正常.
问题是以上不起作用!!!我无法抗拒 – 这不是逻辑! Spock在某个地方的GroovyMockMetaClass中获得了“迷失”.如果我在代码中更改了一行,而在测试中更改了一行就可以了.
代码更改:
From: def input = (cons.readLine(prompt).trim()?:defValue)?.toString() To: (add the null param) def input = (cons.readLine(prompt,null).trim()?:defValue)?.toString()
测试变更:
From: 1 * consoleMock.readLine(_) >> 'validResponse' To: (again,add a null param) 1 * consoleMock.readLine(_,null) >> 'validResponse'
然后测试终于起作用了.这是Spock中的一个错误,还是我只是在左外野?我不介意需要做任何可能在测试工具中需要的东西,但必须修改代码才能使这项工作真的非常糟糕.
解决方法
>创建新类MockConsole,不是从Console继承,但具有相同的方法.@H_502_18@>以这种方式更改MyClass的构造函数:
MyClass(cons = null){@H_502_18@ this.cons = cons?:System.console()@H_502_18@}@H_502_18@>在spock测试中实例化MockConsole并将其传递给MyClass构造函数.
更新201312272156
我玩了一点spock.模拟“readLine(String fmt,Object … args)”的问题似乎特定于varargs(或者最后arg是一个列表,这与groovy相同).我设法将问题减少到以下场景:
定义一个接口:
interface IConsole { String readLine(String fmt,Object ... args) }
定义测试:
class TestInputMethods extends Specification { def 'test console input'() { setup: def consoleMock = GroovyMock(IConsole) 1 * consoleMock.readLine(_) >> 'validResponse' when: // here we get exception "wrong number of arguments": def testResult = consoleMock.readLine('testPrompt') then: testResult == 'validResponse' } }
这个测试变体失败,异常“参数数量错误”.特别是,spock认为readLine接受2个参数而忽略了第二个参数是vararg的事实.证明:如果我们从IConsole.readLine中删除“Object … args”,则测试成功完成.
以下是针对此(希望是临时的)问题的解决方法:将对readLine的调用更改为:
def testResult = consoleMock.readLine('testPrompt',[] as Object[])
然后测试成功完成.
我也尝试了针对spock 1.0-groovy-2.0-SNAPSHOT的相同代码 – 问题是一样的.
更新201312280030
varargs的问题解决了!非常感谢@charlesg,他回答了我的相关问题:Spock: mock a method with varargs
解决方案如下:用Mock替换GroovyMock,然后正确解释varargs.