我正在使用Jest为Node / Express / Mongo项目设置测试。我试图写一个函数来清除集合,所以每个测试都以一个干净的平板开始:
const clearCollection = (collectionName, done) => {
const collection = mongoose.connection.collections[collectionName]
collection.drop(err => {
if (err) throw new Error(err)
else done()
)
}
beforeEach(done => {
clearCollection('users', done)
})
另一个尝试,承诺:
const clearCollection = collectionName => {
const collection = mongoose.connection.collections[collectionName]
return collection.drop()
}
beforeEach(async () => {
await clearCollection('users')
})
问题是它们在工作和抛出错误之间交替。每次我保存文件时,它都可以正常工作,或者每次都交替抛出错误。错误始终是以下之一:
MongoError: cannot perform operation: a background operation is currently running for collection auth_test.users
MongoError: ns not found
通过让clearCollection()
在catch()
中调用自己,我可以让它在100%的时间内工作(无论如何都受到堆栈限制),但这感觉很错误:
const clearCollection = collectionName => {
const collection = mongoose.connection.collections[collectionName]
return collection.drop()
.catch(() => clearCollection(collectionName))
}
我不知道为什么mongoose.connection.collections.<collection>.drop()
会随机抛出错误,但是有一种简单的方法可以删除Mongoose中的所有文件,这对于在测试之前重置集合非常有用:
beforeAll(async () => {
await User.remove({})
})
每次都有效。
尝试在测试开始时删除数据库并在之后填充数据库时,我遇到了类似的问题。在第一次运行中,将创建集合;在下一个,我会得到一个错误,'数据库正在被丢弃。'; ......它像这样交替。
我还在使用“内存”Mongodb,在运行我的Mocha测试之前在单独的终端窗口中运行$ run-rs -v 4.0.0 -s
(https://www.npmjs.com/package/run-rs)。另外,我在这里有Mongoose 5.2.0和Mocha 5.1.1。
我发现Mongoose不一定立即执行drop命令。相反,它会在连接启动时安排它们。
因此,可能存在竞争条件,其中drop命令的承诺得到解决,并且您继续执行代码,直到达到创建集合的指令...但是drop命令尚未完成运行,并且您'将获得创建新集合的错误。运行完成后,下次运行测试时,您的数据库(或集合)已被删除,因此您将能够再次插入新集合。
所以,这就是我解决的问题......
在前钩子中运行:
test.dropDb = function(done) {
this.timeout(0)
let database = your_MongoDB_URI
mongoose.connect(database, function (err) {
if (err) throw err;
mongoose.connection.db.dropDatabase(function(err, result){
console.log('database dropping was scheduled');
});
})
mongoose.connection.on('connected', function() {
setTimeout(function(){ done() }, 3000);
});
}
在嵌套之前运行钩子
test.createDb = function(done) {
this.timeout(0)
let createDb = require('./create-db.js')
createDb() // here I call all my MyCollections.insertMany(myData)...
.then( function() {
done()
})
.catch( function(err) {
assert( null == err)
});
}
在后钩中运行
test.afterAll = function(done) {
mongoose.connection.close()
.then( function() {
done()
})
}
我不知道为什么我必须在挂钩后显式关闭连接。我想这与run-rs
的编程方式有关,但我没有调查它。我只知道,在我的情况下,在测试之后关闭连接是强制性的,以获得预期的行为。