【问题标题】:Spock mocks showing up as nullsSpock 模拟显示为空值
【发布时间】:2016-01-28 10:44:29
【问题描述】:

这是我的主要课程:

@Slf4j
class ConsoleReaderWorker implements Runnable {
    ConsoleReader reader
    Writer writer
    RemoteCommandSelector commandSelector

    @Inject
    ConsoleReaderWorker(ConsoleReader reader, Writer writer, RemoteCommandSelector commandSelector) {
        super()
        this.reader = reader
        this.writer = writer
        this.commandSelector = commandSelector
    }

    @Override
    void run() {
        try {
            String line
            while ((line = reader.readLine()) != null) {
                commandSelector.select(line).execute(writer)
                writer.flush()
            }
        } catch(InterruptedException ex) {
            log.warn("${this} interrupted with: ${ExceptionUtils.getStackTrace(ex)}")
        }
    }
}

这是我对 Spock Specification 的尝试:

class ConsoleReaderWorkerSpec extends Specification {
    def "when enter key is pressed then a command is selected and executed and the writer is flushed"() {
        given: "a running fixture with some mock dependencies"
        ConsoleReader reader = Mock(ConsoleReader)
        Writer writer = Mock(Writer)
        RemoteCommand command = Mock(RemoteCommand)
        RemoteCommandSelector commandSelector = Mock(RemoteCommandSelector)

        reader.readLine() >> '\n'
        commandSelector.select(_) >> command

        ConsoleReaderWorker worker = new ConsoleReaderWorker(reader, writer, commandSelector)

        when: "the enter key is pressed"
        worker.run()

        then: "a command is executed"
        1 * commandSelector.select(_)
    }
}

基本上,我想确认当run() 方法被调用时,commandSelector#select() 方法是用any 参数调用的。

当我运行它时,我得到:

java.lang.NullPointerException: Cannot invoke method execute() on null object
    at com.nocbots.nbsvc.remote.cli.jline.ConsoleReaderWorker.run(ConsoleReaderWorker.groovy:33)
    at com.nocbots.nbsvc.remote.cli.jline.ConsoleReaderWorkerSpec.when enter key is pressed then a command is selected and executed and the writer is flushed(ConsoleReaderWorkerSpec.groovy:25)

ConsoleReadyWorker 的第 33 行是对位于 while 循环内的 commandSelector.select() 的调用:

commandSelector.select(line).execute(writer)

关于为什么的任何想法?!?如您所见,我已连接 commandSelector#select() 模拟以返回 RemoteCommand 模拟,因此它永远不应该为空......想法?

【问题讨论】:

    标签: unit-testing groovy spock


    【解决方案1】:

    试试:

    then: "a command is executed"
    1 * commandSelector.select(_) >> command
    

    代替:

    commandSelector.select(_) >> command
    

    请查看docs。当你同时模拟和验证时,应该使用then 块。

    编辑

    这是您遇到的与 spock 相关的错误,相信我。看看下面的可运行脚本(可以使用 groovy 控制台运行):

    @Grab('org.spockframework:spock-core:1.0-groovy-2.4')
    @Grab('cglib:cglib-nodep:3.1')
    
    import spock.lang.*
    
    class ConsoleReaderWorkerSpec extends Specification {
        def "when enter key is pressed then a command is selected and executed and the writer is flushed"() {
            given: "a running fixture with some mock dependencies"
            ConsoleReader reader = Mock(ConsoleReader)
            Writer writer = Mock(Writer)
            RemoteCommand command = Mock(RemoteCommand)
            RemoteCommandSelector commandSelector = Mock(RemoteCommandSelector)
    
            reader.readLine() >> '\n'
    
            ConsoleReaderWorker worker = new ConsoleReaderWorker(reader, writer, commandSelector)
    
            when: "the enter key is pressed"
            worker.run()
    
            then: "a command is executed"
            1 * commandSelector.select(_) >> command
        }
    }
    
    class ConsoleReaderWorker implements Runnable {
    
        ConsoleReader reader
        Writer writer
        RemoteCommandSelector commandSelector
    
        ConsoleReaderWorker(ConsoleReader reader, Writer writer, RemoteCommandSelector commandSelector) {
            this.reader = reader
            this.writer = writer
            this.commandSelector = commandSelector
        }
    
        @Override
        void run() {
            try {
                String line
                while ((line = reader.readLine()) != null) {
                    commandSelector.select(line).execute(writer)
                    writer.flush()
                }
            } catch(InterruptedException ex) {
                log.warn("${this} interrupted with: ${ExceptionUtils.getStackTrace(ex)}")
            }
        }
    }
    class Writer {
       void flush() {}
    }
    class RemoteCommand {
       void execute(Writer w) {
    
       }
    }
    class ConsoleReader {
       String readLine() {
          ''
       }
    }
    class RemoteCommandSelector {
       RemoteCommand select(o) {
          new RemoteCommand()
       }
    }
    

    因为select 被调用了两次,所以它失败了,但不会因为 NPE 而失败。要修复它,请添加以下行:

    reader.readLine() >>> ['\n', null]
    

    【讨论】:

    • 感谢@Opal (+1) - 但是 heh?!? 请仔细查看我的 Spock 规范。我的代码 是 在 then 块之后(实际上,逐字逐句:then: "a command is executed")。我的模拟是(再次逐字):1 * commandSelector.select(_)。 最重要的是它甚至不是我得到的与 Spock 相关的错误。如果您阅读了我的问题,您会看到我在主课中获得了 NPE,因为 Spock 没有(出于某种原因)正确地尊重我设置的模拟。我觉得你没有完全阅读我的问题。如果您这样做了,请提供一个完整 代码示例,以便将您的答案放在更好的上下文中。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2015-08-03
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    • 1970-01-01
    • 2022-06-22
    • 1970-01-01
    相关资源
    最近更新 更多