在测试兔子消费者时,如何在microaut中模拟带有spock的服务?



我目前正在处理:

  • Micronaut 3.7.3
  • RabbitMQ 3.11.2
  • Spock
  • Groovy/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块中的任何其他指令之前。

我建议不要在你的代码中使用任何类型的睡眠。最好的情况是你只是徒劳地等待,最坏的情况是你没有等待足够长的时间,你的测试中断了。最好使用一个或多个CountDownLatch实例来同步您的测试。
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)和一个宽松的超时,以防止您的测试无限期挂起。

最新更新