13.1.3 测试 R2DBC Repository

Spring Data R2DBC 支持为 R2DBC Repository 编写集成测试类。具体来说,@DataR2dbcTest 注解放在测试类上时,会导致 Spring 使用生成的 Spring Data R2DBC Repository 作为 bean 来创建应用程序上下文,并注入到测试类中。就像我们在上一章中使用的 StepVerifier,这使我们能够针对我们创建的所有 Repository 编写自动化测试类。

为了简洁起见,我们将只关注一个测试类:IngredientRepositoryTest。这将测试 IngredientRepository,验证它是否可以保存 Ingredient 对象、获取单一 Ingredient,并获取所有保存的 Ingredient 对象。清单 13.7 显示了这个测试类。

清单 13.7 测试 Spring Data R2DBC Repository。

package tacos.data;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest;

import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import tacos.Ingredient;
import tacos.Ingredient.Type;

@DataR2dbcTest
public class IngredientRepositoryTest {

  @Autowired
  IngredientRepository ingredientRepo;

  @BeforeEach
  public void setup() {
    Flux<Ingredient> deleteAndInsert = ingredientRepo.deleteAll()
      .thenMany(ingredientRepo.saveAll(
      Flux.just(
        new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
        new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
        new Ingredient("CHED", "Cheddar Cheese", Type.CHEESE)
      )));
    StepVerifier.create(deleteAndInsert)
          .expectNextCount(3)
          .verifyComplete();
  }

  @Test
  public void shouldSaveAndFetchIngredients() {

    StepVerifier.create(ingredientRepo.findAll())
      .recordWith(ArrayList::new)
      .thenConsumeWhile(x -> true)
      .consumeRecordedWith(ingredients -> {
        assertThat(ingredients).hasSize(3);
        assertThat(ingredients).contains(
          new Ingredient("FLTO", "Flour Tortilla", Type.WRAP));
        assertThat(ingredients).contains(
          new Ingredient("GRBF", "Ground Beef", Type.PROTEIN));
        assertThat(ingredients).contains(
          new Ingredient("CHED", "Cheddar Cheese", Type.CHEESE));
      })
      .verifyComplete();

    StepVerifier.create(ingredientRepo.findBySlug("FLTO"))
      .assertNext(ingredient -> {
        ingredient.equals(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP));
    });
  }

}

shouldSaveAndFetchIngredients() 方法首先创建 Flux<Ingredient> 对象。从这个 Flux 中,它使用 flatMap() 操作通过注入的 IngredientRepository 上的 save() 方法保存每一个 Ingredient。调用 subscribe() 将打开通过 Flux 的数据流,导致 Ingredient 对象被保存。

接下来,从 Repository 的 findBySlug() 方法返回的 Mono<Ingredient>,创建出了一个 StepVerifier,这。Mono<Ingredient> 中应该有一个 Ingredient 对象。也是 assertNext() 方法验证的内容,这是一个 slug 值为 “FLTO”的 Ingredient 对象。最后,验证了 Mono 的完整性。

最后,根据 Repository 的 findAll() 方法返回的 Flux<Ingredient>,创建出了另一个 StepVerifier。一次一个,它断言,从该 Flux 流出的 Ingredient 与最初测试开始时保存的三个 Ingredient 对象相匹配。与其他 StepVerifier 一样,对 verifyComplete() 的调用验证 Mono 是完整的,没有更多的 Ingredient 对象流出了。

虽然我们只专注于测试 IngredientRepository,但同样的技术也可以应用于测试任何 Spring Date R2BDC 的 Repository。

到目前为止,一切顺利。我们现在已经定义了领域类型及其各自的 Repository。我们已经编写了一个测试类来验证它们是否有效。如果您愿意,我们可以就这样使用。但是这些 Repository 使 TacoOrder 的持久性变得不方便,因为您必须首先创建和持久化属于该 TacoOrder 的 Taco 对象,然后持久化属于该 TacoOrder 对象。当您查看 TacoOrder 时,您只会得到 Taco ID 而不是完整的 Taco 对象集合。

如果我们能够将 TacoOrder 作为聚合根,与拥有的所有 Taco 对象一起持久化,那就太好了。那样,如果我们找到一个 TacoOrder,就能得到完整的 Taco对象(而不仅仅是 ID)。让我们定义一个 Service 级别类,该类位于 OrderRepository 和 TacoRepository 之上,以模拟第 3 章的 OrderRepository 的行为。

results matching ""

    No results matching ""