jest"> jest"> 使用 Jest 测试 Mongoose

Jest 是 Facebook 开发的 JavaScript 运行时,通常用于测试。由于 Jest 主要用于测试 React 应用程序,因此将其用于测试 Node.js 服务器端应用程序会带来很多问题。我们强烈建议使用其他测试框架,例如 Mocha

要抑制 Mongoose 的任何 Jest 警告,请设置 SUPPRESS_JEST_WARNINGS 环境变量

env SUPPRESS_JEST_WARNINGS=1 npm test

如果您选择深入危险水域并使用 Jest 测试 Mongoose 应用程序,那么您需要了解以下内容

如果您使用的是 Jest <=26,请不要在测试 Mongoose 应用程序时使用 Jest 的默认 jsdom 测试环境除非您明确测试仅使用 Mongoose 的浏览器库 的应用程序。在 Jest >=27 中,"node" 是 Jest 的默认 testEnvironment,因此不再是问题。

jsdom 测试环境试图在 Node.js 中创建一个类似浏览器的测试环境,它带有许多令人不快的意外,例如 模拟的 setTimeout() 函数,该函数在测试结束后会静默失败。Mongoose 通常不支持 jsdom,并且预计在 jsdom 测试环境中无法正常工作。

要将您的 testEnvironment 更改为 Node.js,请将 testEnvironment 添加到您的 jest.config.js 文件中

module.exports = {
  testEnvironment: 'node'
};

计时器模拟

绝对不要在测试 Mongoose 应用程序时使用 计时器模拟。如果您使用的是 Jest >=25,这一点尤其重要,因为它会模拟 process.nextTick()

伪计时器会模拟 setTimeout()setInterval() 等全局函数,当底层库使用这些函数时会导致问题。Mongoose 和 MongoDB Node.js 驱动程序使用这些函数来将工作推迟到事件循环的下一个滴答,以及监控与 MongoDB 服务器的连接。

如果您绝对必须使用计时器模拟,请确保在调用 useFakeTimers() 之前导入 Mongoose

// Fine for basic cases, but may still cause issues:
const mongoose = require('mongoose');

jest.useFakeTimers();

// Bad:
jest.useFakeTimers();

const mongoose = require('mongoose');

Mongoose 开发人员已经重构了代码以 避免使用 setImmediate() 将工作推迟到事件循环的下一个滴答,但我们无法合理地确保 Mongoose 依赖的每个库都不使用 setImmediate()

更好的替代方法是使用 sinon 创建您自己的 setTimeout() 包装器并模拟它。

// time.js
exports.setTimeout = function() {
  return global.setTimeout.apply(global, arguments);
};

// Tests
const time = require('../util/time');
const sinon = require('sinon');
sinon.stub(time, 'setTimeout');

globalSetupglobalTeardown

不要使用 globalSetup 来调用 mongoose.connect()mongoose.createConnection()。Jest 在 单独的环境 中运行 globalSetup,因此您无法在测试中使用在 globalSetup 中创建的任何连接。

进一步阅读

想学习如何正确测试 Mongoose 应用程序?Pluralsight 上的 使用 Node.js 和 Express 的 RESTful Web 服务 课程有一个关于使用 Mocha 测试 Mongoose 应用程序的优秀部分。

RESTful Web Services with Node.js and Express