使用带有 NoSQL JUnit @Rule 的 Spring Data 随机(嵌入式)Mongo 端口 [英] Use Spring Data random (embedded) Mongo port with NoSQL JUnit @Rule

查看:67
本文介绍了使用带有 NoSQL JUnit @Rule 的 Spring Data 随机(嵌入式)Mongo 端口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试编写一个使用 Spring Data Mongo 存储库的集成测试类.我使用 de.flapdoodle.embed.mongo 依赖项提供的嵌入式 Mongo 实例.Spring Data 文档指定我们只需将此依赖项放入项目中,其余的由 EmbedMongoAutoConfiguration 处理.

I'm currently trying to write an Integration test class which uses Spring Data Mongo repositories. I use an embedded Mongo instance provided by the de.flapdoodle.embed.mongo dependency. Spring Data documentation specifies that we only have to put this dependency in the project and the EmbedMongoAutoConfiguration takes care of the rest.

现在,没关系,将端口设置为 0 会使自动配置过程找到一个空闲端口来启动 mongo 实例.

For now, that's ok, and setting the port to 0 makes the auto configuration process to find a free port to launch the mongo instance on.

此功能对于我来说是必要的,以避免与其他测试(这些测试与我公司的其他项目一起在 Jenkins CI 服务器上运行)发生冲突.

This feature is necessary for me to avoid collision with other tests (which are run on a Jenkins CI server along with other project of my company).

问题来了,我希望能够在我的每个测试方法运行之前从某个外部文件注入一些测试数据.我发现 NoSQL Unit 可以通过一个简单的方法注释和一个 JUnit @Rule 来做到这一点.

The problem comes now, I want to be able to inject some test data from some external file before each of my test method run. I found out that NoSQL Unit can do this with a simple method annotation and a JUnit @Rule.

这是一个例子:

@Value("${local.mongo.port}")
private int mongoPort; // <- still 0 a the time the Rule below is created.

@Rule
public MongoDbRule managedMongoDb = new MongoDbRule(MongoDbConfigurationBuilder.mongoDb().databaseName("myAwesomeDb").port(mongoPort).build());

@Test
@UsingDataSet(locations = "testdata.json", loadStrategy = LoadStrategyEnum.CLEAN_INSERT)
public void testMyData() {
   // ...
}

我的问题是,@Rule 需要在其构建器中使用 Mongo 端口来实例化底层的 MongoClient,但是在实例化 @Rule 时,Spring 上下文没有完全初始化并且EmbeddedMongoAutoConfiguration 尚未发布端口.

My problem is that, the @Rule needs the Mongo port in its builder to instantiate the underlying MongoClient, but at the time the @Rule is instantiated, the Spring context is not fully initialized and the EmbeddedMongoAutoConfiguration has not published the port yet.

所以我的问题是,有没有人曾经使用 NoSQL Unit 的嵌入式 Mongo 功能,并且有没有办法,例如创建 @Rule after 初始化 Spring 上下文?

So my question is, is there anyone who has ever used the Embedded Mongo feature with NoSQL Unit, and is there any way to, for example create the @Rule after the Spring context is initialized ?

我想知道是否自己找到空闲端口(以静态方式),将其设置为 @Rule 然后告诉 EmbeddedMongoAutoConfiguration 通过覆盖IMongodConfig bean 是个好主意吗?还是有更简单"的方法?

I was wondering if finding the free port myself (in a static way), setting it to the @Rule and then tell the EmbeddedMongoAutoConfiguration to use it by overriding the IMongodConfig bean was a good idea ? or is there a "simpler" way ?

注意:我刚刚看到flappdoodle库提供了一个类和一个静态方法来查找一个空闲的服务器端口,它被Spring这样使用:

Note: I just saw that flapdoodle library provides a class and a static method to find a free server port and its used by Spring like this:

Network.getFreeServerPort(getHost()), Network.localhostIsIPv6()))

提前谢谢大家!

我尝试了上面提到的解决方案,它似乎有效,但我仍然认为它有点冗长"和肮脏.

I tried the solution I talked just above, and it seems to work, though I still think it's a bit "verbose" and dirty.

private static final Logger log = LoggerFactory.getLogger(MyAwesomeIT.class);
private static int mongoPort;
static {
    try {
        mongoPort = Network.getFreeServerPort();
    } catch (IOException e) {
        log.error("Error while trying to find a free port for Mongo", e);
        mongoPort = -1; // test should then not work
    }
}

@Rule
public MongoDbRule managedMongoDb = new MongoDbRule(MongoDbConfigurationBuilder.mongoDb().databaseName("myAwesomeDb").port(mongoPort).build());

然后在关联的配置类中:

then in the associated configuration class :

@Configuration
@EnableAutoConfiguration
@EnableMongoRepositories
@EnableConfigurationProperties(MongoProperties.class)
static class ContextConfiguration {
    @Autowired
    private MongoProperties mongoProperties;

    @PostConstruct
    public void init() {
        // Here, I override the port property
        mongoProperties.setPort(mongoPort);
    }
}

推荐答案

细化@user6599111给出的方案,可以得到Flapdoodle Embedded Mongo随机选择的port,只需注入一个对象IMongodConfig 类型.

Refining the solution given by @user6599111, it is possible to obtain the port randomly chosen by Flapdoodle Embedded Mongo, simply injecting an object of type IMongodConfig.

Spring Boot 自动为你构建这个对象,如所述 此处.

Spring Boot builds automagically this object for you, as stated here.

那么,配置类就会变成下面这样.

Then, the configuration class will become the following.

@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
public class MongoConfiguration {
    @Autowired
    private Environment environment;

    @Autowired
    private MongoProperties properties;

    @Autowired(required = false)
    private MongoClientOptions options;

    @Autowired
    private IMongodConfig mongoConfig;

    @Bean
    public MongoClient mongo() throws Exception {
        properties.setPort(mongoConfig.net().getPort());
        return properties.createMongoClient(this.options, this.environment);
    }
}

这篇关于使用带有 NoSQL JUnit @Rule 的 Spring Data 随机(嵌入式)Mongo 端口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆