反应堆switchIfEmpty并验证执行

时间:2018-09-24 09:10:19

标签: java spring-boot reactive-programming project-reactor java-10

我有一个像这样的简单存储库实现。

@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);
}

在这样的控制器上还有一个简单的动作方法。

    @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>
);

请问我做错了什么。任何指针将不胜感激。

3 个答案:

答案 0 :(得分:1)

能否请您确认在测试中您正在设置一个空的单声道。

请您替换下面的行:

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();

答案 1 :(得分:1)

我遇到了同样的错误,解决方法是使用Mono.defer(()->...)函数中的.switchIfEmpty(),根据此medium的文章,如果期望开关总是执行而不会产生副作用,

答案 2 :(得分:0)

该模拟设置的问题是始终save()被调用。实际存储库返回的Mono是惰性的,因此在订阅之前没有任何反应。 switchIfEmpty的工作是仅在没有收到onNext信号的情况下进行所述订阅。

方法调用就是方法调用。 switchIfEmpty无法阻止save以这种形式执行。好像您有System.out.println(getMessage())之类的东西:getMessage会在执行整行时被调用;)

要进行测试,您可以在模拟中使用reactor-test的{​​{1}}:

PublisherProbe