提问人:michalbarnat 提问时间:11/12/2023 最后编辑:kriegaexmichalbarnat 更新时间:11/14/2023 访问量:55
为什么我的测试在拆分 mocking 和 stubing 时不起作用?
Why does my test not work when splitting mocking and stubbing?
问:
我在 Spock/Groovy 测试中苦苦挣扎。 不知道为什么,但在WHEN部分,我无法检查调用次数并立即检查值。 如果我单独检查其中一个,一切正常!
此测试通过:
def "should throw AppointmentNotFoundException when appointment do not exist" () {
given:
long nonExistingAppointmentId = 69L
when:
appointmentRepository.findById(nonExistingAppointmentId) >> { throw new AppointmentNotFoundException("Appointment with id " + nonExistingAppointmentId + " not found") }
findAppointmentQueryHandler.handle(nonExistingAppointmentId)
then:
thrown(AppointmentNotFoundException)
}
而且这个通过没有任何问题:
def "should throw AppointmentNotFoundException when appointment do not exist" () {
given:
long nonExistingAppointmentId = 69L
when:
appointmentRepository.findById(nonExistingAppointmentId) >> { throw new AppointmentNotFoundException("Appointment with id " + nonExistingAppointmentId + " not found") }
findAppointmentQueryHandler.handle(nonExistingAppointmentId)
then:
1 * appointmentRepository.findById(69L)
}
但是,如果我尝试进行 1 次测试来检查所有测试,那么我就有错误了
def "should throw AppointmentNotFoundException when appointment do not exist" () {
given:
long nonExistingAppointmentId = 69L
when:
appointmentRepository.findById(nonExistingAppointmentId) >> { throw new AppointmentNotFoundException("Appointment with id " + nonExistingAppointmentId + " not found") }
findAppointmentQueryHandler.handle(nonExistingAppointmentId)
then:
1 * appointmentRepository.findById(69L)
thrown(AppointmentNotFoundException)
}
错误:
Expected exception of type 'com.bbc.anotherhospital.exceptions.AppointmentNotFoundException', but no exception was thrown
at org.spockframework.lang.SpecInternals.checkExceptionThrown(SpecInternals.java:84)
at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:71)
at com.bbc.anotherhospital.appointment.handlers.FindAppointmentQueryHandlerSpec.should throw AppointmentNotFoundException when appointment do not exist
首先,我认为我的代码或代码有问题。但是应用程序运行良好,在 Postman 中进行了测试。
有人知道它为什么会这样吗?
我的pom:
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>4.0.15</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>2.4-M1-groovy-4.0</version>
<scope>test</scope>
</dependency>
答:
2赞
kriegaex
11/13/2023
#1
这是 Spock 的常见问题解答,也在 Stack Overflow 上。Spock 手册清楚地解释了为什么你正在做的事情不起作用:
结合嘲笑和存根
嘲笑和存根是相辅相成的:
1 * subscriber.receive("message1") >> "ok" 1 * subscriber.receive("message2") >> "fail"
当模拟和存根相同的方法调用时,它们必须在同一交互中发生。特别是,以下 Mockito 样式的存根和 mocking 拆分为两个单独的语句将不起作用:
given: subscriber.receive("message1") >> "ok" when: publisher.send("message1") then: 1 * subscriber.receive("message1")
如在何处声明交互中所述,调用将首先与块中的交互进行匹配。由于该交互未指定响应,因此将返回方法返回类型(在本例中为)的默认值。(这只是斯波克宽容嘲讽的另一个方面。因此,块中的交互将永远没有机会匹配。
receive
then:
null
given:
注意:同一方法调用的模拟和存根必须在同一交互中发生。
也就是说,你想使用类似的东西
1 * appointmentRepository.findById(nonExistingAppointmentId) >> {
throw new AppointmentNotFoundException("Appointment with id " + nonExistingAppointmentId + " not found")
}
在你的街区。then:
评论
0赞
kriegaex
11/15/2023
其实,现在我有点生气。我的答案是正确的,首先在这里,甚至解释了为什么它没有按照您尝试的方式工作。昨天,我在提交 9765c936 时克隆了您的存储库,并完全按照上述方式更改了 FindAppointmentQueryHandlerSpec
中的此部分。它解决了这个问题。你为什么用相同的解决方案接受后来的答案?
0赞
tim_yates
11/14/2023
#2
我必须添加一些东西,以便我可以运行您的示例,但是:
class TestSpec extends Specification {
def "should throw AppointmentNotFoundException when appointment do not exist" () {
given:
AppointmentRepository appointmentRepository = Mock()
FindAppointmentQueryHandler findAppointmentQueryHandler = new FindAppointmentQueryHandler(appRepository: appointmentRepository)
long nonExistingAppointmentId = 69L
when:
findAppointmentQueryHandler.handle(nonExistingAppointmentId)
then:
def ex = thrown(AppointmentNotFoundException)
ex.message == "Appointment with id $nonExistingAppointmentId not found"
1 * appointmentRepository.findById(69L) >> {
throw new AppointmentNotFoundException("Appointment with id " + nonExistingAppointmentId + " not found")
}
}
static class FindAppointmentQueryHandler {
AppointmentRepository appRepository
String handle(long id) {
appRepository.findById(id)
}
}
static class AppointmentRepository {
String findById(long id) {
"called $id"
}
}
static class AppointmentNotFoundException extends RuntimeException {
AppointmentNotFoundException(String message) {
super(message)
}
}
}
工作?
评论