13.2.3 测试响应式 MongoDB Repository

为 MongoDB Repository 编写测试的关键是使用 @DataMongoTest。此注解执行与 @DataR2dbcTest 类似的功能,这是我们在本章前面使用过的。它确保 Spring 应用程序上下文生成 Repository 相关 bean,并且可注入测试类。从那里,测试类可以使用这些注入的Repository 来设置测试数据,并对其执行其他操作。

例如,考虑清单 13.15 中的 IngredientRepositoryTest 类测试 IngredientRepository,断言 Ingredient 对象可以写入数据库。

清单 13.15 测试响应式 Mongo 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.mongo.DataMongoTest;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import tacos.Ingredient;
import tacos.Ingredient.Type;

@DataMongoTest
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.findById("FLTO"))
      .assertNext(ingredient -> {
        ingredient.equals(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP));
      });
  }

}

此测试与我们前面编写的基于 R2DBC 的 Repository 测试类略有不同。它首先将三个 Ingredient 对象写入数据库。然后使用两个 StepVerifier 验证 Ingredient 是否可以通过 Repository 读到,先获取所有 Ingredient 对象的集合,然后通过 ID 获取单个 Ingredient。

此外,与前面基于 R2DBC 的测试一样,@DataMongoTest 注解将查找添加了 @SpringBootConfiguration 注解的类,以创建应用程序上下文。前面创建的那个,这里也可以使用。

这里的独特之处在于,第一步 StepVerifier 将所有 Ingredient 对象收集到一个 ArrayList,然后断言 ArrayList 包含每个 Ingredient。findAll() 方法不能保证结果文档的顺序,这使得 assertNext()expectNext() 容易失败。通过收集所有产生的Ingredient,将对象放入列表中,我们可以断言该列表包含所有三个对象,而不管它们的顺序如何。

OrderRepository 的测试看起来很类似,如清单 13.16 所示。

清单 13.16 测试 Mongo OrderRepository。

package tacos.data;

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.mongo.DataMongoTest;

import reactor.test.StepVerifier;
import tacos.Ingredient;
import tacos.Taco;
import tacos.TacoOrder;
import tacos.Ingredient.Type;

@DataMongoTest
public class OrderRepositoryTest {

  @Autowired
  OrderRepository orderRepo;

  @BeforeEach
  public void setup() {
    orderRepo.deleteAll().subscribe();
  }

  @Test
  public void shouldSaveAndFetchOrders() {
  TacoOrder order = createOrder();

  StepVerifier
    .create(orderRepo.save(order))
    .expectNext(order)
    .verifyComplete();

  StepVerifier
    .create(orderRepo.findById(order.getId()))
    .expectNext(order)
    .verifyComplete();

  StepVerifier
    .create(orderRepo.findAll())
    .expectNext(order)
    .verifyComplete();

  }
  private TacoOrder createOrder() {
    TacoOrder order = new TacoOrder();
    ...
    return order;
  }

}

shouldSaveAndFetchOrders() 方法所做的第一件事是构造一个订单,有完整的客户和付款信息和一些玉米卷。(为了简洁起见,createOrder() 方法的详细信息被省略。)然后它使用一个 StepVerifier 保存 TacoOrder 对象,并断言 save() 方法返回保存的 TacoOrder。然后尝试通过其 ID 获取订单,并断言它收到了完整的 TacoOrder。最后,它获取所有 TacoOrder 对象(应该只有一个),并断言它是预期的 TacoOrder 对象。

如前所述,您将需要一个 MongoDB 服务器,并侦听端口 27017,以运行此测试。而 Flapdoodle 这个嵌入式 MongoDB 不能很好地与响应式 Repository 配合使用。如果您的计算机上安装了 Docker,则可以轻松启动 MongoDB 服务器,并侦听端口 27017,如下所示:

$ docker run -p27017:27017 mongo

还有其他方法可以获得 MongoDB 服务器。更多细节请参阅以下网址的文档:https://www.mongodb.com/

现在,我们已经了解了如何为 R2BDC 和 MongoDB 创建响应式 Repository,下面让我们看一看另一个 Spring Data 选择:Cassandra。

results matching ""

    No results matching ""