Spock:使用GroovyMock进行不必要的实际方法调用

时间:2018-03-16 17:30:35

标签: groovy mocking spock

我有这样的测试

def "fileField should be set for each line batch"(){
    given:
    LuceneEngine le = new LuceneEngine()
    le.indexWriter = Mock( IndexWriter ){
        addDocument(_) >> null 
    }
    le.currentFilename  = 'dummy filename'
    le.fileField = GroovyMock( TextField )

    when:
    le.processLineBatch([ 'dummy text' ], 0 )

    then:
    1 * le.fileField.setStringValue( 'dummy filename' ) >> null         

}

app方法如下所示:

def processLineBatch( List lineBatch, int deliveryNo ) {
    String lDocText = lineBatch.join( '\n' ).trim()
    textField.setStringValue( lDocText )
    fileField.setStringValue( currentFilename )
    indexWriter.addDocument( singleLDoc )
}

我必须将GroovyMock用于TextField,因为该课程为final

无论我做什么(我已经尝试过很多事情),实际的方法setStringValue都会被运行......然后生成Exception,因为这是一个模拟。

有关信息,失败的情况如下:

  

java.lang.NullPointerException
at   org.apache.lucene.document.Field.setStringValue(Field.java:307)
在   org.spockframework.mock.runtime.GroovyMockMetaClass.doInvokeMethod(GroovyMockMetaClass.java:86)     在
  org.spockframework.mock.runtime.GroovyMockMetaClass.invokeMethod(GroovyMockMetaClass.java:42)     
at core.LuceneEngine.processLineBatch(lucene_functions.groovy:422)

...其中第422行是fileField.setStringValue (...

这似乎与我对非Groovy模拟的期望相反。谁能解释我的错误以及是否有解决方案?

来自Lucene 6的

NB TextFieldhere ...您可以从中链接到超类Field并看到setStringValue是(非finalpublic void

1 个答案:

答案 0 :(得分:2)

实际上你已经基本上问了同样的问题,你甚至接受了my answer!您需要使用全局 Groovy模拟:

package de.scrum_master.stackoverflow

import org.apache.lucene.document.TextField
import org.apache.lucene.index.IndexWriter
import org.apache.lucene.index.IndexableField

class LuceneEngine {
  TextField textField
  TextField fileField
  IndexWriter indexWriter
  String currentFilename
  Iterable<? extends IndexableField> singleLDoc

  def processLineBatch(List lineBatch, int deliveryNo) {
    String lDocText = lineBatch.join('\n').trim()
    textField.setStringValue(lDocText)
    fileField.setStringValue(currentFilename)
    indexWriter.addDocument(singleLDoc)
  }
}
package de.scrum_master.stackoverflow

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

class LuceneEngineTest extends Specification {
  def "fileField should be set for each line batch"() {
    given:
    LuceneEngine le = new LuceneEngine()
    le.indexWriter = Mock(IndexWriter) {
      addDocument(_) >> null
    }
    le.currentFilename = 'dummy filename'
    // Assign this to le.textField or le.fileField if you like, it does not
    // make a difference because the Groovy mock is GLOBAL
    GroovyMock(TextField, global: true)

    when:
    le.processLineBatch(['dummy text'], 0)

    then:
    1 * le.fileField.setStringValue('dummy filename') >> null
  }
}

至于为什么你需要在这里使用全局模拟,我无法解释它。这是Spock mailing list的问题。我再次完成了你的工作并在那里发了一个问题。

相关问题