我目前正在处理:
- Micronaut 3.7.3
- RabbitMQ 3.11.2 SpockGroovy/Java 17
我正在为一个简单的演示项目实现一个rabbitmq消费者,遵循microaut项目(https://micronaut-projects.github.io/micronaut-rabbitmq/3.1.0/guide/index.html)的指导方针
我正在尝试模拟一个服务,它是我的rabbitmq消费者的依赖项。
我试过这种方法,但似乎不起作用:
@MicronautTest
@Subject(SampleRequestConsumer)
class SampleRequestConsumerSpec extends Specification {
@Inject
ExternalWorkflowProducer externalWorkflowProducer
@Inject
SampleRequestConsumer sampleRequestConsumer
@Inject
SimpleService simpleService
@MockBean(SimpleService)
SimpleService simpleService() {
Mock(SimpleService)
}
def "It receives a sampleRequest message in the simple.request queue"() {
when:
externalWorkflowProducer.send(new SampleRequest(message: "Request1"))
then:
sleep(100)
1 * simpleService.handleSimpleRequest(_ as SampleRequest) >> { SampleRequest request ->
assert request.message != null
}
}
}
我在运行集成测试时得到这个错误:
Too few invocations for:
1 * simpleService.handleSimpleRequest(_ as SampleRequest) >> { SampleRequest request ->
assert request.message != null
} (0 invocations)
Unmatched invocations (ordered by similarity):
None
查看GitHub上的完整源代码:https://github.com/art-dambrine/micronaut-rabbitmq-spock-mocking/blob/test-with-mq/src/test/groovy/com/company/microproject/amqp/consumer/SampleRequestConsumerSpec.groovy
还请注意,当我没有从队列中读取并直接调用方法sampleRequestConsumer.receive([message: "Request1"])
时模拟simpleService
正在工作:https://github.com/art-dambrine/micronaut-rabbitmq-spock-mocking/blob/test-without-mq/src/test/groovy/com/company/microproject/amqp/consumer/SampleRequestConsumerSpec.groovy
谢谢你的真知灼见
重要请使用test-with-mq
分支。分支test-without-mq
的测试将成功,因为它没有使用rabbitMQ。这是一个尝试,以证明问题在于测试RabbitMQ消费者。
将sleep()
指令移到when:
块中修复了测试。
确实,then:
块后面的东西不是在externalWorkflowProducer.send()
之后执行的,它是在之前被Spock执行的。这个指令:
1 * simpleService.handleSimpleRequest(_ as SampleRequest)
是在特性方法的范围内创建一个交互,并且在配置规范时执行。
在那里添加sleep()
指令,并没有为消费者留下接收消息的规范时间。send()
后需要添加sleep()
。这时你的测试需要让消费者有时间执行。
注意:闭包本身:
{ SampleRequest request ->
assert request.message != null
}
将在之后执行,但只执行闭包。sleep指令在配置Spec时已经执行。Closure在这种情况下没有执行,因为测试在consumer线程调用mock之前就完成了。
在简介:
如此:
def "It receives a sampleRequest message in the simple.request queue"() {
when:
externalWorkflowProducer.send(new SampleRequest(message: "Request1"))
sleep(100)
then:
1 * simpleService.handleSimpleRequest(_ as SampleRequest) >> { SampleRequest request ->
assert request.message != null
}
}
这个不行:
def "It receives a sampleRequest message in the simple.request queue"() {
when:
externalWorkflowProducer.send(new SampleRequest(message: "Request1"))
then:
sleep(100)
1 * simpleService.handleSimpleRequest(_ as SampleRequest) >> { SampleRequest request ->
assert request.message != null
}
}
正如@LuisMuñiz指出的那样,在then
块中声明的相互作用实际上是移动的。它创建了一个包含所有交互的交互作用域,它的设置发生在when
块执行之前,所有交互的验证发生在then
块中的任何其他指令之前。
def "It receives a sampleRequest message in the simple.request queue"() {
given:
def latch = new CountDownLatch(1)
when:
externalWorkflowProducer.send(new SampleRequest(message: "Request1"))
latch.await()
then:
1 * simpleService.handleSimpleRequest(_ as SampleRequest) >> { SampleRequest request ->
assert request.message != null
latch.countDown()
}
}
这样您的测试将等待,直到您mock被调用,但随后立即完成。
您还可以使用latch.await(long timeout, TimeUnit unit)
和一个宽松的超时,以防止您的测试无限期挂起。