我有一个简单的存储库实现,如下所示。
@Repository
public interface PolicyRepository extends ReactiveMongoRepository<Policy, String> {
@Query("{ id: { $exists: true }}")
Flux<Policy> findAllPaged(Pageable pageable);
@Query("{ name: { $eq: ?0 }}")
Mono<Policy> findByName(String name);
}在像这样的控制器上有一个简单的Action方法。
@ResponseStatus(HttpStatus.CREATED)
public Mono<ResponseEntity<String>> createPolicy(@Valid @RequestBody Policy policy) {
//Use The Mongodb ID Generator
policy.setId(ObjectId.get().toString());
return policyRepository.findByName(policy.getName()).flatMap(policy1 -> {
return Mono.just(ResponseEntity.badRequest().body("A Policy with the same name as the policy you are trying to create" +
"already exists"));
}).switchIfEmpty(
policyRepository.save(policy).map(p2 ->{
eventPublisher.publish(Events.POLICY_CREATED, p2.getId());
return ResponseEntity.status(HttpStatus.CREATED).body("Policy definition created successfully");
}));
}我希望实现的是,如果存在与要插入的策略同名的策略,则返回一个错误的请求,或者如果findByName方法返回空,则执行保存操作。
奇怪的行为是下面的测试失败了,因为无论findByName是否返回数据,save总是被调用。
下面是测试结果
@Test
void testCreateDuplicatePolicyShouldFail() {
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.just(policy));
given(policyRepository.save(any(Policy.class))).willReturn(Mono.just(policy));
given(eventPublisher.publish(Events.POLICY_CREATED, policy.getId())).willReturn(Mono.just(0L));
webTestClient.post().uri("/policies")
.syncBody(policy)
.exchange()
.expectStatus().isBadRequest();
verify(policyRepository, times(1)).findByName(eq(policy.getName()));
verify(policyRepository, times(0)).save(any(Policy.class));
verify(eventPublisher, times(0)).publish(Events.POLICY_CREATED, policy.getId());
}并且它会失败,并出现以下异常
org.mockito.exceptions.verification.NeverWantedButInvoked:
com.management.dashboard.repository.PolicyRepository#0 bean.save(
<any com.management.core.model.Policy>
);我是不是做错了什么。任何指针都将被深深地感谢。
发布于 2018-09-29 07:12:34
这种模拟设置的问题是save()总是被调用。由实际存储库返回的Mono是惰性的,因此在订阅它之前什么都不会发生。并且switchIfEmpty的工作是仅当它没有接收到onNext信号时才进行所述订阅。
方法调用就是一个方法调用。switchIfEmpty不能做任何事情来阻止以这种形式执行save。这就好像您有类似于System.out.println(getMessage())的东西:每当执行整行时都会调用getMessage ;)
为了进行测试,您可以在模拟中使用reactor-test的PublisherProbe:
@Test
void testCreateDuplicatePolicyShouldFail() {
//set up a probe to verify that the save Mono is never triggered
PublisherProbe probe = PublisherProbe.of(Mono.just(policy));
//now let the `save` return the probe:
given(policyRepository.save(any(Policy.class))).willReturn(probe.mono());
//rest of the mock and invocation is same
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.just(policy));
given(eventPublisher.publish(Events.POLICY_CREATED, policy.getId())).willReturn(Mono.just(0L));
webTestClient.post().uri("/policies")
.syncBody(policy)
.exchange()
.expectStatus().isBadRequest();
verify(policyRepository, times(1)).findByName(eq(policy.getName()));
verify(eventPublisher, times(0)).publish(Events.POLICY_CREATED, policy.getId());
//but we now actually expect the save() to be invoked, but the probe to be inert:
verify(policyRepository, times(1)).save(any(Policy.class));
probe.assertWasNotSubscribed();
}发布于 2018-09-25 09:38:02
你能确认你在测试中设置了一个空的单声道吗?
您可以替换下面的行吗:
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.just(policy));使用这一行:
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.empty());仅当流为空时才调用switchIfEmpty运算符。此外,您还可以启用日志来跟踪流。这可以通过在switchIfEmpty之后添加一个日志操作符来完成。例如:
return policyRepository.findByName()
.switchIfEmpty()
.log();https://stackoverflow.com/questions/52475968
复制相似问题