### Question:
StatisticsService extends ReactorStatisticsServiceGrpc.StatisticsServiceImplBase { @Override public Flux<StatisticsServiceProto.DataPoint> listDataPoints(Mono<StatisticsServiceProto.ListDataPointsRequest> request) { return request.flatMapMany(req -> Flux.defer(() -> Flux.fromStream(dataPointRepository.listByAccountName(req.getAccountName()))) .switchIfEmpty(Flux.error( Status.NOT_FOUND .withDescription("No statistics found for account '" + req.getAccountName() + "'") .asRuntimeException() ) ).subscribeOn(jdbcScheduler) ).map(this::toDataPointProto); }  @Override Flux<StatisticsServiceProto.DataPoint> listDataPoints(Mono<StatisticsServiceProto.ListDataPointsRequest> request);  }### Answer:
@Test void shouldListDataPoints() { when(repository.listByAccountName(ACCOUNT_NAME)).thenReturn(Stream.of( stubDataPoint(DATE_1, SAVING_AMOUNT, salary()), stubDataPoint(DATE_2, SAVING_AMOUNT, grocery(), vacation()) )); StepVerifier.create(statisticsService.listDataPoints(stubListDataPointsRequest())) .expectNextMatches(dp -> { assertThat(dp.getAccountName()).isEqualTo(ACCOUNT_NAME); assertThat(dp.getDate()).isEqualTo(dateConverter().convert(DATE_1)); assertThat(dp.getMetricsList()).extracting( StatisticsServiceProto.ItemMetric::getType, StatisticsServiceProto.ItemMetric::getTitle, StatisticsServiceProto.ItemMetric::getMoneyAmount ).containsExactlyInAnyOrder( tuple(StatisticsServiceProto.ItemType.INCOME, SALARY, SALARY_PROTO_AMOUNT) ); assertThat(dp.getStatisticsMap()).containsOnly( new SimpleEntry<>(StatisticalMetric.INCOMES_AMOUNT.name(), SALARY_PROTO_AMOUNT), new SimpleEntry<>( StatisticalMetric.EXPENSES_AMOUNT.name(), bigDecimalConverter().convert(BigDecimal.ZERO) ), new SimpleEntry<>(StatisticalMetric.SAVING_AMOUNT.name(), SAVING_PROTO_AMOUNT) ); return true; }).expectNextMatches(dp -> { assertThat(dp.getAccountName()).isEqualTo(ACCOUNT_NAME); assertThat(dp.getDate()).isEqualTo(dateConverter().convert(DATE_2)); assertThat(dp.getMetricsList()).extracting( StatisticsServiceProto.ItemMetric::getType, StatisticsServiceProto.ItemMetric::getTitle, StatisticsServiceProto.ItemMetric::getMoneyAmount ).containsExactlyInAnyOrder( tuple(StatisticsServiceProto.ItemType.EXPENSE, GROCERY, GROCERY_PROTO_AMOUNT), tuple(StatisticsServiceProto.ItemType.EXPENSE, VACATION, VACATION_PROTO_AMOUNT) ); assertThat(dp.getStatisticsMap()).containsOnly( new SimpleEntry<>( StatisticalMetric.INCOMES_AMOUNT.name(), bigDecimalConverter().convert(BigDecimal.ZERO) ), new SimpleEntry<>(StatisticalMetric.EXPENSES_AMOUNT.name(), EXPENSES_PROTO_AMOUNT), new SimpleEntry<>(StatisticalMetric.SAVING_AMOUNT.name(), SAVING_PROTO_AMOUNT) ); return true; }).verifyComplete(); }
@Test void shouldFailToListDataPoints() { when(repository.listByAccountName(ACCOUNT_NAME)).thenReturn(Stream.empty()); StepVerifier.create(statisticsService.listDataPoints(stubListDataPointsRequest())) .expectErrorMatches(e -> { assertThat(Status.fromThrowable(e).getCode()).isEqualTo(Status.Code.NOT_FOUND); assertThat(e.getCause()).isNull(); return true; }).verify(); }