Реактор switchIfEmpty и проверка выполнения - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть простая реализация репозитория, подобная этой.

@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 возвращает пустое значение.

Странное поведение состоит в том, что следующий тест завершается неудачно, потому что всегда вызывается save независимо от того, возвращает ли findByName данные или нет.

Вот этот тест

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

Пожалуйста, я делаю что-то не так.Любой указатель будет высоко оценен.

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

Проблема с этой фиктивной настройкой заключается в том, что save() IS всегда вызывается.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();

}
0 голосов
/ 25 сентября 2018

Можете ли вы подтвердить, что в тесте вы устанавливаете пустой моно.

Можете ли вы заменить нижнюю строку:

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