在单独的文件中对 Mongoose 模型进行单元测试会导致问题(使用 Mockgoose & Lab)

Posted

技术标签:

【中文标题】在单独的文件中对 Mongoose 模型进行单元测试会导致问题(使用 Mockgoose & Lab)【英文标题】:Unit testing Mongoose models in separate files causes issues (using Mockgoose & Lab) 【发布时间】:2016-06-10 02:07:41 【问题描述】:

每当 Mongoose 模型在加载后尝试加载时,都会抛出错误,例如:

错误:uncaughtException:编译后无法覆盖Account 模型。日期=2016 年 2 月 26 日星期五 10:13:40 GMT-0700 (MST),pid=19231,uid=502,gid=20,cwd=/Users/me/phpstormProjects/project,execPath=/usr/local/Cellar/节点/0.12.4/bin/node, 版本=v5.2.0, argv=[/usr/local/Cellar/node/0.12.4/bin/node, /usr/local/Cellar/node/0.12.4/bin /lab], rss=73306112, heapTotal=62168096, heapUsed=29534752, loadavg=[1.6005859375, 1.84716796875, 1.8701171875], 正常运行时间=648559 OverwriteModelError: 编译后无法覆盖Account 模型。

我没问题,但现在我正在为我的模型编写单元测试,我遇到了一个问题。

只是一些关于文件结构的基本信息......

我将所有 Mongoose 模型放在单独的文件中,位于 src/models/ 文件夹中,要加载这些模型,只需需要该文件夹,将 Mongoose 对象传递给它,然后将 src/models/index.js 文件将加载所有模型,并返回模型对象。 index.js 文件可以看到here (和它无关,但模型名称基本上是文件名,没有 .js

现在,模型的单元测试也被拆分为单独的文件。每个模型都有一个测试文件。尽管每个单元测试文件都专注于特定模型,但其中一些也使用其他模型(用于之前/之后的任务)。

最初的问题

我刚刚创建了第二个单元测试文件,当我独立执行每个测试文件时,它们工作得很好。但是当我执行所有这些时,我收到上述错误,说明我正在尝试多次加载模型。由于我在每个单元测试用例中都需要 ./models,因此我正在多次加载它们。

第一次解决尝试

我想也许我可以通过 after() 在每个单独的单元测试文件中清除所有加载的模型,如下所示:

after(function(done) 
    mongoose.connection.close(function() 
        mongoose.connection.models = 
        done()
    )
)

这根本不起作用(没有新错误,但相同的一旦编译就无法覆盖Account 模型错误仍然存​​在)

第二次解决尝试(半成功)

而不是模型在最后一行抛出错误,当它尝试返回Mongoose.model()时,我在模型顶部插入了一些逻辑,以检查模型是否已加载,如果是,则返回 那个模型对象:

const thisFile  = path.basename( __filename ).match( /(.*)\.js$/ )[ 1 ]
const modelName = _.chain( thisFile ).toLower().upperFirst().value()

module.exports = Mongoose => 
    // Return this model, if it already exists
    if( ! _.isUndefined( Mongoose.models[ modelName ] ) )
        return Mongoose.models[ modelName ]

    const Schema = Mongoose.Schema

    const appSchema = new Schema( /* ..schema.. */)

    return Mongoose.model( modelName, appSchema )

我现在正在我的模型中尝试这个,它似乎工作正常,(好的意思是我没有收到上面列出的错误,说我正在多次加载模型)

新问题

现在每当执行单元测试时,我都会收到一个错误,每个模型都会显示一次错误,但它是相同的错误:

$ lab

  ..................................................
  ...

Test script errors:

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

There were 3 test script error(s).

53 tests complete
Test duration: 1028 ms
No global variable leaks detected

在那个堆栈跟踪中没有太多细节可以忽略..

我不确定它是否是由我添加到每个模型中的代码引起的,检查它是否已经加载,如果是,它会在我执行单个单元测试时显示,或者它只会显示 无法设置属性 '0' of undefined 两次(一次用于成功的初始模型加载,然后两次用于接下来的两次......我想)

如果有人有任何意见,我将非常感激!谢谢

更新

我尝试运行lab --debug 以获取更多信息,虽然它没有显示出现的错误周围的任何堆栈跟踪,但它使它们加倍......这很奇怪。所以如果只执行lab时有2个,lab --debug会显示4个

另外,我使用Winston 进行日志记录。如果我将日志级别更改为调试,这会在控制台中显示 lot 的调试条目,它不会显示围绕这些错误的任何条目......所以这让我认为这可能不是造成的通过我的脚本,而是单元测试依赖项中的某些内容?

错误说它们源自 error.js 文件,但别说太多了。我试图通过find . -name 'events.js' 找到一个error.js,没有结果.. 奇怪

【问题讨论】:

【参考方案1】:

我认为您在每个模型中放置的代码都是 hack。在正常执行过程中,require 具有“全局”作用——模块一旦导入,就不会再次导入。

这个正常流程可能在测试期间发生了变化,但这意味着最好找到一个可以在测试中本地实现的解决方案。

您似乎也遇到了与本期讨论的问题相似的问题 - OverwriteModelError with mocha 'watch'。

有一些解决方案可以尝试:

1) 每次创建新的猫鼬连接:

var db = mongoose.createConnection()

2) 通过 nodemon 运行 mocha。这个对我来说看起来很令人费解,但仍然值得尝试,也许它可以让每个测试完全独立运行。我还假设您使用 mocha 进行测试:

nodemon --exec "mocha -R min" test

3) 每次测试后清除猫鼬模型和方案:

after(function(done)
  mongoose.models = ;
  mongoose.modelSchemas = ;
  mongoose.connection.close();
  done();
);

【讨论】:

我其实也是这么想的,但只有当错误显示比测试文件少一个时才有意义。这意味着如果我有 5 个使用 Mongoose/Mockgoose 的单元测试文件,那么如果你是对的,我会认为 id 只看到错误 4 次,但我看到了 5 次,除非我只执行一个,或者只存在一个。无论如何,我尝试了您的解决方案,但它似乎不起作用。 @Justin 你可以为你的问题创建一个mvce 吗?我想我可以找到包含完整代码示例的解决方案。 你有github用户吗?我会把你添加到私人仓库,它使用 Mockgoose,所以你不必创建 Mongo DB

以上是关于在单独的文件中对 Mongoose 模型进行单元测试会导致问题(使用 Mockgoose & Lab)的主要内容,如果未能解决你的问题,请参考以下文章

在单独的模块中定义 Mongoose 模型

单独文件上的 Mongoose 子文档,如何嵌入它们

如何在打字稿中对模型接口进行单元测试?

如何在 Laravel 中对调用另一个模型的方法的模型方法进行单元测试

Nest.js 在单元测试中无法解析 Mongoose 模型依赖

MongoDB / Mongoose 单元测试 - 最佳实践? [关闭]