使用 Junit 5 和 Micronaut 设置测试 MongoDBContainer

Setting Test MongoDBContainer with Junit 5 and Micronaut

尝试使用 Junit 5 和 micronaut 设置测试 MongoDBContainer,而不是使用 application.yml 配置在测试环境的随机端口上启动 MongoDB。

application.yml

micronaut:
  application:
    name: feteBirdProductConsumer

mongodb:
  uri: "mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017}"
  database: "FeteBird-Product"

Junit测试

@MicronautTest
@Testcontainers
public class ProductListenerTest {
    private final IProductProducer iProductProducer;
    @Container
    private final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"));

    public ProductListenerTest(IProductProducer iProductProducer) {
        this.iProductProducer = iProductProducer;
    }

    @BeforeEach
    @DisplayName("Mongo Db container starting")
    void mongoDbContainerStarting() {
        mongoDBContainer.start();
    }

    @Test
    @DisplayName("Check if Mongo db container is up")
    void checkIfMongoDbContainerIsUp() {
        Assertions.assertTrue(mongoDBContainer.isRunning());
    }


    @Test
    @DisplayName("Should search based on the name")
    void shouldSearchBasedOnTheName() {
        iProductProducer.findFreeText("string").subscribe(item -> {
            System.out.println(item);
        });
    }
}

shouldSearchBasedOnTheName 方法中,return 值来自 application.yml MongoDB 配置。

在测试环境中,我没有向 MongoDB 插入任何值,但是该方法 return 从应用程序 MongoDB

中获取了值

我想我缺少 mongoDb 的配置,但不太确定如何设置

更新

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ProductListenerTest implements TestPropertyProvider {
@Nonnull
    @Override
    public Map<String, String> getProperties() {
        mongoDBContainer.start();
        String address = mongoDBContainer.getHost();
        Integer port = mongoDBContainer.getFirstMappedPort();
        return CollectionUtils.mapOf(
                "MONGO_HOST", address,
                "MONGO_PORT", port
        );
    }
}

异常

com.mongodb.MongoSocketReadException: Prematurely reached end of stream

您启动的测试容器绑定了一个随机端口,您需要手动将其提供给 Micronaut,两者之间没有自动集成。我不认为你可以使用 @MicronautTest 来解决这个问题,因为它甚至在容器初始化之前就运行了应用程序上下文。但是您仍然可以自己配置和启动上下文:

@Testcontainers
public class ProductListenerTest {
    @Container
    private MongoDBContainer mongoDBContainer = 
                     new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"));
    private ApplicationContext context;
    private MongoClient client;

    @BeforeEach
    void mongoDbContainerStarting() {
        mongoDBContainer.start();
        // Overwrite the mongodb.uri value from your configuration file
        context = ApplicationContext.run(
                      Map.of("mongodb.uri", mongoDBContainer.getReplicaSetUrl()));
        client = context.getBean(MongoClient.class);
    }

Micronaut 需要从 MongoDBContainer 获取连接 URL,因此使用 MicronautTest 不会像使用特殊“tc”数据库的 SQL 容器那样工作 URLs。 JUnit 答案类似于我对 Spock 使用的答案,

@Testcontainers
class MongoControllerSpec extends Specification {

    @Shared
    MongoDBContainer mongo = new MongoDBContainer("mongo:4.1.1")
            .withExposedPorts(27017)

    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer

    @Shared
    @AutoCleanup
    RxHttpClient rxClient

    def setupSpec() {
        embeddedServer = ApplicationContext.run(EmbeddedServer,
                ['mongodb.uri': mongo.getReplicaSetUrl("micronaut")])
        rxClient = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL())
    }

    ...
}