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 ""