我目前正在使用mongoDB,我希望可以在任何机器上运行集成和功能测试(目前在专用构建服务器和未来的CI服务器中)。
主要问题是我必须能够检查mongodb安装(如果不存在,安装它),在启动时启动mongodb实例并在进程完成后将其关闭。
这里有一个已经开发的问题Embedded MongoDB when running integration tests建议安装gradle或maven插件。
这个gradle插件https://github.com/sourcemuse/GradleMongoPlugin/可以执行此操作,但我必须使用它来管理我的依赖项,已经尝试过了。这种方法的问题本身并不是问题,但是当我尝试这个时,我已经失去了IDE(STS,intellij)的所有好处。
有没有人设法做到这一点?
如果某人配置grails与grails项目同时失去了grails的观点,我也会感谢你的帮助!
谢谢!
特里夫。
答案 0 :(得分:2)
我最近为此创建了一个grails插件。 https://github.com/grails-plugins/grails-embedded-mongodb
目前它是快照,但我打算本周发布一个版本
答案 1 :(得分:0)
我使用内存中的Mongo服务器进行集成测试,效果很好。它运行速度快,不需要启动单独的Mongo服务器或处理特殊的grails或maven配置。这意味着测试可以与任何JUnit测试运行器同样良好地运行,即在任何IDE或构建系统中运行。无需额外设置。
我也使用了" flapdoodle"嵌入式mongo服务器进行测试。它使用不同的方法,因为它为真正的Mongo实例下载并执行单独的进程。我发现这个机制有更多移动部件,而且当我真正想做的就是验证我的应用程序与mongo服务器是否正常工作时,对我来说似乎有些过分。
答案 2 :(得分:0)
迟到最好的回答 -
不幸的是,我发现Fongo并没有很好地满足我的所有要求 - 最值得注意的是,$eval
未实现,因此您无法使用Mongeez等迁移工具运行集成测试。
我选择EmbedMongo,我通过JUnit ExternalResource
规则在我的Spock / Geb集成测试中使用它。尽管加里是正确的,他说真正的托管数据库带有更多移动部件,但我发现我宁愿冒这个风险,也不愿依靠模拟实现。到目前为止,它工作得很好,在测试套件拆解期间提供或采取不干净的数据库关闭,幸运的是,这不会影响测试。您可以按如下方式使用规则:
@Integration(applicationClass = Application)
@TestFor(SomeGrailsArtifact) // this will inject grailsApplication
class SomeGrailsArtifactFunctionalSpec extends Specification {
@Shared @ClassRule
EmbedMongoRule embedMongoRule = new EmbedMongoRule(grailsApplication)
@Rule
ResetDatabaseRule resetDatabaseRule = new ResetDatabaseRule(embedMongoRule.db)
...
为了完整起见,这些是规则实现:
EmbedMongoRule.groovy
import org.junit.rules.ExternalResource
import com.mongodb.MongoClient
import com.mongodb.MongoException
import de.flapdoodle.embed.mongo.MongodProcess
import de.flapdoodle.embed.mongo.MongodStarter
import de.flapdoodle.embed.mongo.config.IMongodConfig
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder
import de.flapdoodle.embed.mongo.config.Net
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.process.runtime.Network
/**
* Rule for {@code EmbedMongo}, a managed full-fledged MongoDB. The first time
* this rule is used, it will download the current production MongoDB release,
* spin it up before tests and tear it down afterwards.
*
* @author Michael Jess
*
*/
public class EmbedMongoRule extends ExternalResource {
private def mongoConfig
private def mongodExecutable
public EmbedMongoRule(grailsApplication) {
if(!grailsApplication) {
throw new IllegalArgumentException(
"Got null grailsApplication; have you forgotten to supply it to the rule?\n" +
"\n" +
"@Integration(applicationClass = Application)\n" +
"@TestFor(MyGrailsArtifact)\n // will inject grailsApplication" +
"class MyGrailsArtifactSpec extends ... {\n" +
"\n" +
"\t..." +
"\t@Shared @ClassRule EmbedMongoRule embedMongoRule = new EmbedMongoRule(grailsApplication)\n" +
"\t...\n" +
"}")
}
mongoConfig = grailsApplication.config.grails.mongodb
}
@Override
protected void before() throws Throwable {
try {
MongodStarter starter = MongodStarter.getDefaultInstance()
IMongodConfig mongodConfig = new MongodConfigBuilder()
.version(Version.Main.PRODUCTION)
.net(new Net(mongoConfig.port, Network.localhostIsIPv6()))
.build()
mongodExecutable = starter.prepare(mongodConfig)
MongodProcess mongod = mongodExecutable.start()
} catch (IOException e) {
throw new IllegalStateException("Unable to start embedded mongo", e)
}
}
@Override
protected void after() {
mongodExecutable.stop()
}
/**
* Returns a new {@code DB} for the managed database.
*
* @return A new DB
* @throws IllegalStateException If an {@code UnknownHostException}
* or a {@code MongoException} occurs
*/
public def getDb() {
try {
return new MongoClient(mongoConfig.host, mongoConfig.port).getDB(mongoConfig.databaseName)
} catch (UnknownHostException | MongoException e) {
throw new IllegalStateException("Unable to retrieve MongoClient", e)
}
}
}
ResetDatabaseRule.groovy - 自GORM ignores the grails.mongodb.databaseName
parameter as of org.grails.plugins:mongodb:4.0.0
(grails 3.x)以来目前无效
import org.junit.rules.ExternalResource
/**
* Rule that will clear whatever Mongo {@code DB} is provided.
* More specifically, all non-system collections are dropped from the database.
*
* @author Michael Jess
*
*/
public class ResetDatabaseRule extends ExternalResource {
/**
* Prefix identifying system tables
*/
private static final String SYSTEM_TABLE_PREFIX = "system"
private def db
/**
* Create a new database reset rule for the specified datastore.
*
* @param getDb Closure returning a reference to the {@link DB} instance
* to reset.
*/
ResetDatabaseRule(db) {
this.db = db
}
@Override
protected void before() throws Throwable {
db.collectionNames
.findAll { !it.startsWith(SYSTEM_TABLE_PREFIX) }
.each { db.getCollection(it).drop() }
}
}