首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Reactor switchIfEmpty和验证执行

Reactor switchIfEmpty和验证执行
EN

Stack Overflow用户
提问于 2018-09-24 17:10:19
回答 3查看 4.5K关注 0票数 1

我有一个简单的存储库实现,如下所示。

代码语言:javascript
运行
复制
@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方法。

代码语言:javascript
运行
复制
    @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总是被调用。

下面是测试结果

代码语言:javascript
运行
复制
@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());
    }

并且它会失败,并出现以下异常

代码语言:javascript
运行
复制
org.mockito.exceptions.verification.NeverWantedButInvoked: 
com.management.dashboard.repository.PolicyRepository#0 bean.save(
    <any com.management.core.model.Policy>
);

我是不是做错了什么。任何指针都将被深深地感谢。

EN

回答 3

Stack Overflow用户

发布于 2018-09-29 07:12:34

这种模拟设置的问题是save()总是被调用。由实际存储库返回的Mono是惰性的,因此在订阅它之前什么都不会发生。并且switchIfEmpty的工作是仅当它没有接收到onNext信号时才进行所述订阅。

方法调用就是一个方法调用。switchIfEmpty不能做任何事情来阻止以这种形式执行save。这就好像您有类似于System.out.println(getMessage())的东西:每当执行整行时都会调用getMessage ;)

为了进行测试,您可以在模拟中使用reactor-testPublisherProbe

代码语言:javascript
运行
复制
@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();

}
票数 4
EN

Stack Overflow用户

发布于 2018-09-25 09:38:02

你能确认你在测试中设置了一个空的单声道吗?

您可以替换下面的行吗:

代码语言:javascript
运行
复制
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.just(policy));

使用这一行:

代码语言:javascript
运行
复制
given(policyRepository.findByName(eq(policy.getName()))).willReturn(Mono.empty());

仅当流为空时才调用switchIfEmpty运算符。此外,您还可以启用日志来跟踪流。这可以通过在switchIfEmpty之后添加一个日志操作符来完成。例如:

代码语言:javascript
运行
复制
 return policyRepository.findByName()
                        .switchIfEmpty()
                        .log();
票数 1
EN

Stack Overflow用户

发布于 2020-07-10 06:23:24

根据这篇medium文章,我遇到了同样的错误,解决方案是在.switchIfEmpty()函数中使用Mono.defer(()->...),根据这篇medium文章,预计due开关将始终执行而不会产生副作用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52475968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档