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

Spock:final类的mocking/stubing void方法

倪举
2023-03-14

这里的模拟类是org.apache.lucene.document.textfieldsetStringValuevoid

我的规格是这样的...

given:
    ...
    TextField textFieldMock = GroovyMock( TextField )
    // textField is a field of the ConsoleHandler class, ch is a Spy of that class
    ch.textField = textFieldMock
    // same results with or without this line: 
    textFieldMock.setStringValue( _ ) >> null
    // NB I explain about this line below:
    textFieldMock.getClass() >> Object.class

对应的app代码看起来是这样的:

    assert textField != null
    singleLDoc.add(textField)
    writerDocument.paragraphIterator.each{

        println( "textField == null? ${ textField == null }" )
        println( "textField ${ textField.getClass() }" )

        textField.setStringValue( it.textContent ) // NB this is line 114
        indexWriter.addDocument( singleLDoc )

println的输出为

textField == null? false
textField class java.lang.Object
textField == null? false
textField null
java.lang.NullPointerException
at org.apache.lucene.document.Field.setStringValue(Field.java:307)
at org.spockframework.mock.runtime.GroovyMockMetaClass.doInvokeMethod(GroovyMockMetaClass.java:86)
at org.spockframework.mock.runtime.GroovyMockMetaClass.invokeMethod(GroovyMockMetaClass.java:42)
at core.ConsoleHandler.parse_closure1(ConsoleHandler.groovy:114)

在我看来,似乎发生了一些有趣的事情:好像Spock在自言自语:“啊,这个类TextFieldFinal,所以我将咨询它的父类,并从那里使用方法SetStringValue...我发现/决定它不是一个模拟...”

为什么setStringValue没有被嘲弄(或“替换”或任何正确的方法术语...)?

稍后

我去看了一下这个包中的field.java。相关的行有:

  public void setStringValue(String value) {
    if (!(fieldsData instanceof String)) {
      throw new IllegalArgumentException("cannot change value type from " + fieldsData.getClass().getSimpleName() + " to String");
    }
    if (value == null) {
      throw new IllegalArgumentException("value must not be null");
    }
    fieldsData = value;
  }

...第307行(涉及NPE)是第一个抛出新的IllegalArgumentException...行。挺奇怪的。提示fieldsdatanull(如您所料)。

但是为什么Spock会发现自己正在处理类field中的这段代码呢?不合逻辑:这是嘲弄,吉姆,但不是我们所知道的。

PPS解决方案我没有得到任何结果,最后只是创建了一个包装类,它封装了有问题的finaltextfield(并将生成所需的任何方法……)。

我在过去有过与Lucene类作斗争的经历:这些类中的许多都是final或具有final方法。在任何人提出您不需要测试已经可以信任的包之前(我同意这一点!),您仍然需要在开发代码时测试您自己对此类类的使用。

共有1个答案

欧阳高昂
2023-03-14

我真的无法解释为什么它不能像预期的那样为您工作--顺便说一句,截短getClass()是一个坏主意,也是一个坏例子,因为它可能会产生各种副作用--但我确实有一个解决方法给您:使用全局模拟。

第一个特征方法复制了有问题的测试用例,第二个方法展示了如何解决它。

package de.scrum_master.stackoverflow

import org.apache.lucene.document.TextField
import spock.lang.Specification

class LuceneTest extends Specification {
  def "Lucene text field normal GroovyMock"() {

    given: "normal Groovy mock"
    TextField textField = GroovyMock() {
      stringValue() >> "abc"
    }

    when: "calling parent method"
    textField.setStringValue("test")

    then: "exception is thrown"
    thrown NullPointerException

    and: "parent method stubbing does not work"
    textField.stringValue() == null
  }

  def "Lucene text field global GroovyMock"() {

    given: "global Groovy mock"
    TextField textField = GroovyMock(global: true) {
      stringValue() >> "abc"
    }

    expect: "can call parent method"
    textField.setStringValue("test")

    and: "parent method stubbing works"
    textField.stringValue() == "abc"
  }
}
 类似资料:
  • Mocking Bird 是一个实时语音克隆项目,可在 5 秒内克隆声音并生成任意语音内容。 特性 支持普通话并使用多种中文数据集进行测试:aidatatang_200zh, magicdata, aishell3, biaobei, MozillaCommonVoice, data_aishell 等 适用于 Pytorch,已在 1.9.0 版本(最新于 2021 年 8 月)中测试,GPU

  • 我正在使用Powermock为Jersey web服务构建测试用例,并试图模拟数据库函数调用,特别是PUT和POST调用。然而,我在这方面遇到了一些问题。 下面是其中一个web服务调用的样子: 以及我的测试用例当前的样子: 当运行时,这给了我一个断言错误: 意外的方法调用WebService。runUpdateQuery(“exec spInsertApplication,[“测试服务名称”,空,

  • 我有以下情况: 现在我必须测试A.方法()- 当调用b.method2()时,它显然不做任何事情,但我实际上希望它进入b.method2()以最终调用c.method3()。现在c.method3()是我想使用的Mockito.when(c.method3())。返回(1); 这可能吗?如果是,我如何实现这一点?

  • 我试图模仿一个私有方法,如下所示。但是,在第4行,JUnit正在调用相关的validateLanguage方法,并且由于私有方法validateLanguage在调用其他方法时引发了异常,因此没有返回模拟值。我的理解是,使用PowerMock的JUnit应该跳过validateLanguage实际实现的调用。有人能澄清一下吗?

  • Google Mock的设计灵感来源于jMock和EasyMock,它的作用是帮你快速地做出一个接口的仿制品。如果你的设计依赖其它的类,而这些类还没有完成或非常昂贵(如数据库);如果你要测试你的模块与其它模块是否能正确结合,并想了解其交互过程;那么Google Mock就能帮助你。 Google C++ Mocking Framework (or Google Mock for short) is

  • 尝试对定义为以下内容的方法进行单元测试: 在我的测试类中,我将测试方法定义为 当运行这个测试方法时,我在调用的方法(mymethod())中得到NullPointerExcishop。int[]结果是空的。我的理解是它应该从模拟中的存根中得到结果。请帮助我理解我做错了什么。