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

用Spock模拟“阻塞”方法调用?

明松
2023-03-14

注意:这个示例非常简单,但它得到了我想要实现的跨越的想法。

我有一个类(称为Listener),它接受java.net.ServerSocket作为构造函数参数;它有一个StartListing方法,该方法生成一个执行以下操作的新线程(为简洁起见,大大减少了):

while(listening) {
    try {
        Socket socket = serverSocket.accept();
        doSomethingWithSocket(socket);
    } catch(IOException ex) {
        ex.printStackTrace();
        listening = false;
    }
}

在正常操作中,serversocket.accept()调用会阻塞,直到与serversocket建立连接为止。

given: "A ServerSocket, Socket, and Listener"
    def serverSocket = Mock(ServerSocket)
    def socket = Mock(Socket)
    serverSocket.accept() >> socket
    def listener = new Listener(serverSocket)

when: "Listener begins listening"
    listener.startListening()

then: "Something should be done with the socket"
    // Verify some behavior on socket
1.._ * socket.someMethod()

但这让我产生了错误的感觉;我不是真的在寻找至少一个互动,我真的在寻找一个互动。

我可以这样做(返回一次模拟的套接字,然后返回null):

serverSocket.accept() >>> [socket, null]

但是,我仍然有大量对DoSomethingWithSocket的调用,这些调用传递一个null参数,然后我必须检查并忽略(或报告)该参数。如果忽略它,我可能会错过报告一个合法的问题(我认为ServerSocket#Accept不能返回null,但是由于类不是final类,可能有人实现了他们自己的版本,这可以),但是如果我报告它,我的测试日志就会被日志消息污染,日志消息将预期结果报告为意外结果。

serverSocket.accept() >> socket >> {while(true) {}; null }

在调用accept方法之前,这将一直循环;我不是100%确定为什么,因为我认为直到第二次调用accept方法才会对闭包进行计算?

我也试过这个:

serverSocket.accept() >>> [socket, { while(true){}; null }]

根据我的理解,当首次调用accept方法时,将返回socket。进一步的调用将调用闭包,闭包无限循环,因此应该阻塞。

共有1个答案

东龙野
2023-03-14

单元测试应该只测试一个类,而不依赖于其他类。从您粘贴的代码中,您只需要验证两件事

  1. 该类使用提供的套接字重复调用doSomethingWithSocket
  2. 它在引发IO异常后停止

假设doSomething被传递给委托类DoSomethingDelegate

setup:
def delegate = Mock(DoSomethingDelegate)
List actualExceptions = [null,null,new IOException()]
int index = 0
// other setup as in your question

when:
new Listener(serverSocket).startListening()

then:
noExceptionThrown()
3 * delegate.doSomethingWithSocket(socket) {
  if(actualExceptions[index]) {
    throw actualExceptions[index]
  }
  index++
}
setup:
List sockets = []
sockets << Mock(Socket)
sockets << Mock(Socket)
// repeat as needed
socket[3].isClosed() >> {Thread.sleep(1000);false}
serverSocket.accept() >> {sockets[socketNumber]}
// add different mock behavior
// when block
// then
where:
socketNumber << [1,2,3]
 类似资料:
  • 我正在学习使用Spock进行单元测试,遇到了一个我似乎无法理解的问题: 注意:这个例子非常简化,但它得到了我想要实现的概念。 在正常操作中,调用会阻塞,直到建立到的连接。 我希望能够测试返回的上的交互。我可以通过以下方式与Spock一起做到这一点: 乍一看,这工作得很好,只是对的每次调用都将返回经过嘲弄的。由于此调用(有意地)被调用的次数不确定(因为我想接受不确定数量的入站连接),所以mock上的

  • 我试图为一个类编写一个单元测试,这个类使用带有库中的的Google vision API。问题是,由于某种原因,我的模拟仍然调用真正的方法,然后抛出一个NPE,这破坏了我的测试。我以前从未在模拟上见过这种行为,我想知道我是不是做错了什么,是不是Spock/Groovy中有bug,还是与Google lib有关?

  • 1)创建groovy项目 2)创建接口: 3)创建spock测试: 有没有更好的方法来“解释”spock被模仿函数的最后一个参数是vararg,因此可以省略它?

  • 我试图在测试中模拟一个调用,但我得到了一个错误,因为它调用了真正的方法,而不是模拟它。 这是我的方法 } 这是我的测试课 测试实际上调用了受保护的方法config Setter,并在设置代理时失败。帮助我理解我在这里做错了什么。

  • 我目前正在为一个groovy应用程序编写单元testcase 有人能告诉我这是不是嘲弄斯波克的两个电话的正确方法?如果没有,那么请引导我走向正确的解决方案。

  • 我有一个用注释的Groovy类,因此它得到一个私有的最终字段,我想测试它的用法。我想继续使用,而不是为了启用测试而进一步公开字段。 我正在使用Spock1.0编写测试,并尝试使用Spock的集成、模拟和截尾功能来完成测试。全局截尾可以帮助我截取调用以获得实际的实例,因此我目前的猜测是: 有趣的是,拦截实际上起作用了,确认类实际上获得了名为“dummy”的类型“logger”的对象