使用 Junit 5 和 Micronaut 设置测试 MongoDBContainer

问题描述

尝试使用 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 方法中,返回值来自 application.yml MongoDB 配置。

在测试环境中,我没有向 MongoDB 插入任何值,但该方法已从应用程序 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”数据库 URL 的 SQL 容器那样工作。 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())
    }

    ...
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...