加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-14 16:22:11 所属栏目:大数据 来源:网络整理
导读:我有一个groovy脚本,使用readline方法通过 java.io.console对象向用户提出一些问题.另外,我用它来询问密码(用于设置HTTPS).我如何使用Spock对这段代码进行单元测试?目前它抱怨该对象是 Java最终对象,无法进行测试.显然,我不是第一个尝试这个的人,所以我想我
我有一个groovy脚本,使用readline方法通过 java.io.console对象向用户提出一些问题.另外,我用它来询问密码(用于设置HTTPS).我如何使用Spock对这段代码进行单元测试?目前它抱怨该对象是 Java最终对象,无法进行测试.显然,我不是第一个尝试这个的人,所以我想我会问.

代码草图看起来像:

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'

然后测试终于起作用了.这是Spock中的一个错误,还是我只是在左外野?我不介意需要做任何可能在测试工具中需要的东西,但必须修改代码才能使这项工作真的非常糟糕.

解决方法

你是对的:因为Console类是final,所以无法扩展.因此,解决方案应朝另一个方向发展:

>创建新类MockConsole,不是从Console继承,但具有相同的方法.
>以这种方式更改MyClass的构造函数:

MyClass(cons = null){
??this.cons = cons?:System.console()
}
>在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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读