我有一个groovy脚本,它通过使用readline方法的java.io.Console对象向用户提问。另外,我用它来询问密码(用于设置HTTPS)。如何使用Spock对此代码进行单元测试?目前,它抱怨该对象是Java final对象,无法测试。显然,我不是第一个尝试这个的人,所以我想我会问。
代码的草图如下所示:
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的建议编辑了每个答案,我做了一个简单的界面:
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'
然后测试终于起作用了。这是斯波克的虫子还是我只是在左外野?我不介意需要做测试工具中可能需要的任何事情,但是必须修改代码来使其工作是非常非常糟糕的。
你是对的:因为控制台类是final的,所以不能扩展它。因此,解决方案应该朝着另一个方向发展:
>
创建新类MockConsole,它不是从Console继承的,但具有相同的方法。
按以下方式更改MyClass的构造函数:
MyClass(cons=null){this.cons=cons?:system.console()}
在spock测试中实例化MockConsole,并将其传递给MyClass构造函数。
更新-201312272156
我和斯波克玩过一点。嘲笑“readline(String fmt,Object...args)”的问题似乎是varargs特有的(或者last 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'
}
}
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。
我有一个文件夹结构如下 当我运行命令时。它只运行Java单元测试(位于*src\test\Java*目录下),而不调用Groovy测试用例。Groovy似乎再也找不到Groovy测试了。 请帮助我在Maven的帮助下启用groovy测试用例执行? 波姆。xml
我是Spock框架的新手,在使用抽象java测试类时遇到了问题。 我想要的是一个groovy测试类,它用一些常用的方法扩展一些其他java抽象类,这些方法反过来扩展规范类。 当我运行GroovyTest类时,我得到以下错误: Org.SpockFramework.Runtime.InvalidSpecException:规范“org.my.package.AbstractTest”未正确编译(Sp
我如何在我的Grails Spock测试中实现Groovy的新特性?每次我尝试,我都会得到一个看起来像这样的堆栈跟踪。Groovy路径是否有一些我可能不知道的限制? JDK 版本: Groovy Verison: Grails版本: 简化代码: } 堆栈跟踪:
经过一些谷歌搜索,我没有找到什么地方,决定玩一下,发现如果我执行所有测试,它会运行良好,即使当我改变类名以匹配文件名时,它也会工作。是否有一种方法可以配置Eclipse/JUnit,使其能够在与文件名不匹配的groovy类上运行测试? HelloWorld.groovy:
我试图用groovy为一个用Java编写的类编写一个测试用例。Java类(名称:helper)中有一个方法,在该方法中获取HttpClient对象并对其调用executeMethod。我试图在groovy测试用例中模拟这个HttpClient.executeMethod(),但不能正确地模拟它。 任何关于它为什么不正确嘲笑的想法。提前致谢
我有一个由Gradle2.4构建的Java库,它将被一些Java6应用程序、一些Java7应用程序、一些Java8应用程序和一些Groovy2.x应用程序使用。因此,为了尽可能地向后兼容,我编写的lib具有和1.6: 但是,我没有理由不能用Groovy/Spock编写单元测试。只要Groovy不是main/compile/runtime类路径的一部分,那么我就可以自由地用任何JVM语言编写测试!我