当前位置: 首页 > 知识库问答 >
问题:

测试使用System.Console()的Groovy类

裴华荣
2023-03-14

我有一个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'

然后测试终于起作用了。这是斯波克的虫子还是我只是在左外野?我不介意需要做测试工具中可能需要的任何事情,但是必须修改代码来使其工作是非常非常糟糕的。

共有1个答案

暴骏奇
2023-03-14

你是对的:因为控制台类是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语言编写测试!我