如何为嵌入式 mongo (flapdoodle) 全局设置 WriteConcern 以修复间歇性测试失败

Posted

技术标签:

【中文标题】如何为嵌入式 mongo (flapdoodle) 全局设置 WriteConcern 以修复间歇性测试失败【英文标题】:How to set WriteConcern globally for embedded mongo (flapdoodle) to fix intermittent test failures 【发布时间】:2016-06-12 08:52:45 【问题描述】:

问题:有没有办法更改 (Flapdoodle) 嵌入式 mongo 的配置,以便我可以保证写入发生在读取之前? 请注意这个问题专门针对 Flapdoodle 的实现,而不是 MongoDB一般的。我只想在测试和配置中应用它(如果可能的话),而不是通过我所有的 Mongo 操作并在任何地方设置写入问题。

详情

我在我的测试环境中使用 Spring + 嵌入式 mongo。 Maven 依赖如下所示:

<dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>1.50.1</version>
        <scope>test</scope>
</dependency>

使用测试配置类:

@Configuration
@EnableAutoConfiguration(exclude =  EmbeddedMongoAutoConfiguration.class )
@EnableMongoRepositories(basePackages = "path.to.repos")
public class TestMongoConfig 
private static final String DESTROY_METHOD_CLOSE = "close";
private static final String DESTROY_METHOD_STOP = "stop";

private static final Logger LOGGER = LoggerFactory.getLogger(TestMongoConfig.class);

@Autowired
private MongoProperties mongoProperties;

@Autowired(required = false)
private MongoClientOptions mongoClientOptions;

@Autowired
private Environment environment;

@Bean(destroyMethod = DESTROY_METHOD_CLOSE)
public MongoClient mongo() throws IOException 
    Net net = mongodProcess().getConfig().net();
    mongoProperties.setHost(net.getServerAddress().getHostName());
    mongoProperties.setPort(net.getPort());
    return mongoProperties.createMongoClient(this.mongoClientOptions, environment);


@Bean(destroyMethod = DESTROY_METHOD_STOP)
public MongodProcess mongodProcess() throws IOException 
    return mongodExecutable().start();


@Bean(destroyMethod = DESTROY_METHOD_STOP)
public MongodExecutable mongodExecutable() throws IOException 
    return mongodStarter().prepare(mongodConfig());


@Bean
public IMongodConfig mongodConfig() throws IOException 
    return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();


@Bean
public MongodStarter mongodStarter() 
    Command command = Command.MongoD;
    IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
            .defaultsWithLogger(command, LOGGER)
            .artifactStore(new ExtractedArtifactStoreBuilder()
                    .defaults(command)
                    .download(new DownloadConfigBuilder()
                            .defaultsForCommand(command).build())
                    .executableNaming(new UserTempNaming()))
            .build();

    return MongodStarter.getInstance(runtimeConfig);

在那个类中它非常标准,只是按照 flapdoodle 的例子。

在 95% 的情况下,这很有效,我的所有测试都通过了。间歇性地一些随机测试失败,例如当我做这样的事情时:

userRepository.customMethodPushToList(user.getId(), aString);
user = userRepository.findOne(user.getId());
assertEquals(2, user.getSomeList().size());

customMethodPushToList 所做的只是将字符串推送到数据库中 User 条目中的列表中。这里没什么特别的。但是有 5% 的时间测试失败。

认为这是因为与写入问题有关...即我在对象更新之前已检索到该对象。

提前致谢。

编辑

在海报回答后,我手动创建了MongoClientOperations

MongoClientOptions mongoClientOptions = MongoClientOptions.builder().writeConcern(WriteConcern.ACKNOWLEDGED).build();

到目前为止一切都很好......

【问题讨论】:

您是使用embeed mongo还是真正的mongo实例进行测试?我遇到了嵌入 mongo 的问题,它使用的是真正的 monogo 实例。提前致谢。 @devanathan 没有 Mongo 的其他实例 【参考方案1】:

我认为在获得 DB(使用 getDatabase())后需要使用的是 withWriteConcern(): http://api.mongodb.com/java/3.0/com/mongodb/async/client/MongoDatabase.html#withWriteConcern-com.mongodb.WriteConcern-

并使用 ACKNOWLEDGED: http://api.mongodb.com/java/3.0/com/mongodb/WriteConcern.html#ACKNOWLEDGED

也可以使用 withReadPreference() http://api.mongodb.com/java/3.0/com/mongodb/async/client/MongoDatabase.html#withReadPreference-com.mongodb.ReadPreference-

并使用primary(): http://api.mongodb.com/java/3.0/com/mongodb/ReadPreference.html#primary--

这将使行为尽可能简单。

【讨论】:

谢谢,但不清楚我如何从TestConfig 获得对数据库本身的引用? MongoClientOptions 似乎是不可变的,否则有一个 WriteConcern 选项 我没有自动装配 MongoClientOptions,而是把 MongoClientOptions mongoClientOptions = MongoClientOptions.builder().writeConcern(WriteConcern.ACKNOWLEDGED).build(); @user2393012 如果您仍想使用@Autowired,您可以使用带有@Bean 注释的方法来创建MongoClientOptions

以上是关于如何为嵌入式 mongo (flapdoodle) 全局设置 WriteConcern 以修复间歇性测试失败的主要内容,如果未能解决你的问题,请参考以下文章

春季启动:ClassNotFoundException de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion

没有端口的嵌入式mongo(完全在内存中)[重复]

是否有嵌入式 MongoDB 的 GUI(Flapdoodle)

为啥我的 Flapdoodle 嵌入式 MongoDB 测试无法运行? (创建 'embeddedMongoServer' 无法启动进程 EOF)

如何为特定的mongo文档实现TTL

如何为 REST API 构建 Mongo 数据库 [关闭]