我正在学习使用Spock进行单元测试,遇到了一个我似乎无法理解的问题:
注意:这个例子非常简化,但它得到了我想要实现的概念。
while(listening) {
try {
Socket socket = serverSocket.accept();
doSomethingWithSocket(socket);
} catch(IOException ex) {
ex.printStackTrace();
listening = false;
}
}
在正常操作中,ServerSocket.Accept()
调用会阻塞,直到建立到ServerSocket
的连接。
我希望能够测试ServerSocket.Accept()
返回的Socket
上的交互。我可以通过以下方式与Spock一起做到这一点:
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
乍一看,这工作得很好,只是对ServerSocket.Accept()
的每次调用都将返回经过嘲弄的Socket
。由于此调用(有意地)被调用的次数不确定(因为我想接受不确定数量的入站连接),所以mocksocket
上的所有交互发生的次数不确定(取决于计算机的速度、运行时间等)
我可以使用交互的基数来指定至少一个交互,如下所示:
1.._ * socket.someMethod()
但这件事让我感觉不对劲;我不是真的在寻找至少一个交互,我是真的在寻找一个交互。
我可以这样做(返回一次模拟的套接字然后为空):
serverSocket.accept() >>> [socket, null]
但我仍然有大量对DoSomethingWithSocket
的调用,这些调用传递一个null
参数,然后我必须检查并忽略(或报告)该参数。如果忽略它,我可能会错过报告合法的问题(我不认为serversocket#accept
会返回null
,但由于类不是最终的,可能有人实现了他们自己的版本,可以这样做),但是如果我报告它,我的测试日志会受到日志消息的污染,该消息将预期的结果报告为意外的结果。
诚然,我不是一个Groovy程序员,而且这是我第一次和Spock一起工作,所以我很抱歉,如果这是一个简单的错误的事情,或者如果我误解了Spock是如何嘲弄的
我试过这个:
serverSocket.accept() >> socket >> {while(true) {}; null }
在调用accept
方法之前,此循环将永远循环;我不是100%确定为什么,因为我认为直到第二次调用accept方法时才会对闭包进行评估?
我也试过这个:
serverSocket.accept() >>> [socket, { while(true){}; null }]
我试图验证的不是阻塞本身;我想验证每个特征方法的一个行为。我可以使用下面David W提供的技术在一个方法中测试许多行为,但是有些行为会根据接受的连接数量、是否遇到了异常、侦听器
是否被告知停止接受连接等等而改变。这将使单一特性方法变得更加复杂,并且难以进行故障排除和文档化。
如果我可以从accept
方法返回定义数量的socket
模拟,然后将该方法设置为块,我就可以单独和确定性地验证所有这些行为,每个feature方法一个。
单元测试应该只测试一个类,而不是对其他类的依赖。从您粘贴的代码来看,您只需要验证两件事
假设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]
如果您需要一个最后的套接字来容纳主线程,您可以像我上面所做的那样使它Hibernate。您可以通过使方法调用彼此交互来添加更复杂的行为。
注意:这个示例非常简单,但它得到了我想要实现的跨越的想法。 我有一个类(称为),它接受作为构造函数参数;它有一个方法,该方法生成一个执行以下操作的新线程(为简洁起见,大大减少了): 在正常操作中,调用会阻塞,直到与建立连接为止。 但这让我产生了错误的感觉;我不是真的在寻找至少一个互动,我真的在寻找一个互动。 我可以这样做(返回一次模拟的套接字,然后返回null): 但是,我仍然有大量对的调用,这些
1)创建groovy项目 2)创建接口: 3)创建spock测试: 有没有更好的方法来“解释”spock被模仿函数的最后一个参数是vararg,因此可以省略它?
我目前正在为一个groovy应用程序编写单元testcase 有人能告诉我这是不是嘲弄斯波克的两个电话的正确方法?如果没有,那么请引导我走向正确的解决方案。
我试图为一个类编写一个单元测试,这个类使用带有库中的的Google vision API。问题是,由于某种原因,我的模拟仍然调用真正的方法,然后抛出一个NPE,这破坏了我的测试。我以前从未在模拟上见过这种行为,我想知道我是不是做错了什么,是不是Spock/Groovy中有bug,还是与Google lib有关?
我正在处理一个Spring Boot java服务,该服务包含一个Camel处理器类,如下所示: 当我运行它时,我得到一个失败,声明对1*LogService.Update(_)的调用太少(0个调用)。我试着调试代码,在MyProc中,语句被命中,并且logService对象在高亮显示时(在Eclipse中)状态为“mock for type logService named$spock_shar
我试图在测试中模拟一个调用,但我得到了一个错误,因为它调用了真正的方法,而不是模拟它。 这是我的方法 } 这是我的测试课 测试实际上调用了受保护的方法config Setter,并在设置代理时失败。帮助我理解我在这里做错了什么。