测试猫鼬预保存钩子

Posted

技术标签:

【中文标题】测试猫鼬预保存钩子【英文标题】:Testing mongoose pre-save hook 【发布时间】:2018-03-04 08:49:01 【问题描述】:

我对测试 nodejs 还是很陌生。所以我的方法可能是完全错误的。我尝试在不访问数据库的情况下测试 mongoose 模型预保存挂钩。这是我的模型:

// models/user.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

UserSchema = new Schema(
    email: type: String, required: true,
    password: type: String, required: true    
);

UserSchema.pre('save', function (next) 
    const user = this;
    user.email = user.email.toLowerCase();
    // for testing purposes
    console.log("Pre save hook called");
    next();
);

module.exports = mongoose.model("User", UserSchema);

正如我所说,我不想用我的测试访问数据库,所以我尝试使用 Users save() 方法的 sinon 存根:

// test/models/user.js
const sinon = require("sinon");
const chai = require("chai");
const assert = chai.assert;

const User = require("../../models/user");

describe("User", function()
    it("should convert email to lower case before saving", (done) => 
        const user = new User(email: "Valid@Email.com", password: "password123");
        const saveStub = sinon.stub(user, 'save').callsFake(function(cb) cb(null,this) )

        user.save((err,res) => 
            if (err) return done(err);
            assert.equal(res.email,"valid@email.com");
            done();
        )
    )
);

但是,如果我这样做,则不会调用预保存挂钩。我是在错误的道路上还是我错过了什么?或者是否有另一种触发预保存钩子并测试其结果的方法?提前非常感谢!

【问题讨论】:

【参考方案1】:

我刚刚遇到了同样的问题,并设法通过从钩子中提取逻辑来解决它,从而可以单独对其进行测试。隔离是指不测试任何与 Mongoose 相关的东西。

您可以通过创建一个执行您的逻辑的函数来做到这一点,其结构如下:

function preSaveFunc(next, obj) 
  // your logic
  next();

然后你可以在你的钩子中调用它:

mySchema.pre('save', function (next)  preSaveFunc(next, this); );

这将使对 this 的引用在函数内部可用,因此您可以使用它。

然后可以通过将下一个函数覆盖为没有主体的函数来对提取的部分进行单元测试。

希望这对任何人都有帮助,因为我对 Mongoose 的了解有限,解决这个问题实际上很痛苦。

【讨论】:

【参考方案2】:

在我们开始之前:我正在寻找和你一样的东西,但我还没有找到一种方法来测试 Mongoose 中的不同钩子而不需要数据库。区分测试代码和测试 mongoose 很重要。

验证是中间件。默认情况下,Mongoose 将验证注册为每个模式的 pre('save') 挂钩。 http://mongoosejs.com/docs/validation.html

考虑到验证将始终添加到模型中,并且我希望测试模型中的自动化字段,我已从 save 切换到 validate

UserSchema = new Schema(
  email: type: String, required: true,
  password: type: String, required: true    
);

UserSchema.pre('validate', function(next) 
  const user = this;
  user.email = user.email.toLowerCase();
  // for testing purposes
  console.log("Pre validate hook called");
  next();
);

测试现在看起来像:

it("should convert email to lower case before saving", (done) => 
    const user = new User(email: "VALID@EMAIL.COM", password: "password123");
    assert.equal(res.email,"valid@email.com");

那么 Pre Save Hook 呢?

因为我已将自动字段的业务逻辑从“保存”移至“验证”,所以我将使用“保存”进行数据库特定操作。记录、将对象添加到其他文档等。只有与数据库集成才能对此进行测试。

【讨论】:

以上是关于测试猫鼬预保存钩子的主要内容,如果未能解决你的问题,请参考以下文章

如何测试猫鼬预钩“保存”和bcryptjs

Nest.js/Mongoose:为啥我的预保存钩子无法触发?

在猫鼬预中间件中,我如何访问更新查询?

如何在创建猫鼬模型时保存记录?

我的猫鼬测试失败,除非我反复检查我保存在数据库中的数据

保存阵列猫鼬