使用Jest测试具有数据库调用的功能

时间:2018-09-06 19:53:00

标签: mongodb mongoose jestjs

我是Jest和代码测试的新手。我想测试一个使用mongoose从mongodb数据库检索数据的函数。当我运行测试时,我正在测试的函数中对db的所有调用均返回null。测试需要从数据库检索数据的功能的推荐方法是什么?

让我知道您是否需要代码示例或更多信息。

更新:

这是我的代码:

code.js

...
function buildText(listing, messageRule, reservation, isReview = false, isLastMinuteMessage = false) {
    return new Promise(async function(resolve) {
        const name = reservation.name;
        try {
            message = await Message.findOne({
                listingID: listing._id,
                messageRuleID: messageRule._id,
                reservationID: reservation._id,
                message: {$exists: true}
            });
        } catch (error) {
            console.error(error);
        }
        if (message) {
            text = message.message;
        } else {
            text = messageRule.message;
            if (isLastMinuteMessage) {
                text = messageRule.lastMinuteMessage;
            }
        }
        text = text.replace(/{{Guest Name}}/g, name);
        resolve(text);
    });
}
...

code.test.js

const Code = require("./code");
describe("funcs", () => {
    it("buildText", async () => {
        let listing = {
            _id: "1324",
            pricingEnabled: true,
            listingFound: true,
            hideListing: null
        };
        let messageRule = {
            _id: "3452345",
            minNights: 1,
            reviewEnabled: false,
            disableMessageAfterReview: false,
            message: 'test',
            lastMinuteMessage: 'test2'
        };
        let reservation = {
            _id: "63452345",
            hasLeftReview: true,
            hasIssues: false
        };
        let isReview = false;
        let isLastMinuteMessage = false;
        let response = await Code.buildText(listing, messageRule, reservation, isReview, isLastMinuteMessage);
        expect(response).toMatchSnapshot();
    });
});

我遇到的麻烦是代码文件中的message = await Message.findOne({行。它总是返回null,但我需要能够告诉它返回true或false。我该怎么办?

3 个答案:

答案 0 :(得分:1)

这是一个基于提供的代码的简单工作示例:


code.js

const { Message } = require('./message');

function buildText(listing, messageRule, reservation, isReview = false, isLastMinuteMessage = false) {
  return new Promise(async function (resolve) {
    let message, text;
    const name = reservation.name;
    try {
      message = await Message.findOne({
        listingID: listing._id,
        messageRuleID: messageRule._id,
        reservationID: reservation._id,
        message: { $exists: true }
      });
    } catch (error) {
      console.error(error);
    }
    if (message) {
      text = message.message;
    } else {
      text = messageRule.message;
      if (isLastMinuteMessage) {
        text = messageRule.lastMinuteMessage;
      }
    }
    text = text.replace(/{{Guest Name}}/g, name);
    resolve(text);
  });
}

module.exports = {
  buildText
}

code.test.js

const Code = require('./code');
const { Message } = require('./message');

describe("funcs", () => {
  it("buildText", async () => {
    const mock = jest.spyOn(Message, 'findOne');  // spy on Message.findOne()
    mock.mockImplementation(() => Promise.resolve({
      message: 'the message'
    }));  // replace the implementation

    let listing = {
      _id: "1324",
      pricingEnabled: true,
      listingFound: true,
      hideListing: null
    };
    let messageRule = {
      _id: "3452345",
      minNights: 1,
      reviewEnabled: false,
      disableMessageAfterReview: false,
      message: 'test',
      lastMinuteMessage: 'test2'
    };
    let reservation = {
      _id: "63452345",
      hasLeftReview: true,
      hasIssues: false
    };
    let isReview = false;
    let isLastMinuteMessage = false;
    let response = await Code.buildText(listing, messageRule, reservation, isReview, isLastMinuteMessage);
    expect(response).toMatchSnapshot();

    mock.mockRestore();  // restore Message.findOne()
  });
});

message.js(示例的虚拟模型)

const mongoose = require('mongoose');

exports.Message = mongoose.model('Message', new mongoose.Schema({ }));

答案 1 :(得分:0)

我对buildText并不是100%的确定(尽管我从未使用过new Promise(async ...),但对我来说看起来不错)-因此,我将重点放在测试上:据我所知,您正在做基本的事情。唯一的事情是您没有

// jest.mock('mongoose'); doesn't work, unfortunately
const mReal = require('mongoose');
const mMock = mReal; 

然后添加一个beforeAll之类的

    beforeAll(() => { // not 110% clean, but I'm not alone: https://github.com/facebook/jest/issues/936#issuecomment-214556122
        mMock.model = jest.fn(); // manually overwrite one fct with a mock
    });

code.test.js的第一行;加号:您需要先训练模拟,然后在开始时it插入

    it("...", () => {
        const findOneMock = jest.fn();
        findOneMock.mockReturnValue(Promise.resolve({message: "hey"}));
        mMock.model.mockReturnValue({findOne: findOneMock});
        // prep done, test something

我使用了一些简单的测试代码,我想您的代码将等效:

        let res = await mMock.model('whatever').findOne('whatever');
        expect(res.message).toBe("hey");
    });

希望我对所有隐藏的细节(例如您对Message的看法)正确无误-但是,现在,您应该真正解决某些问题。

答案 2 :(得分:0)

如果使用的是开玩笑,那么最好的方法是定义一个名为setup.js的文件,该文件将在运行任何测试文件之前运行,然后在该文件中,导入猫鼬模型,然后建立连接您的测试数据库。 (这是因为您的测试文件与服务器文件是分开运行的,并且对猫鼬模型或数据库连接一无所知,因此,通过定义此文件并建立连接,您可以为测试环境定义猫鼬,并且可以将其用作您想要的而不是null)

您需要完成三个步骤:

  1. 首先在package.json中运行,以告诉jest在运行任何其他测试文件之前先运行文件的内容,您需要在脚本块之前添加此块:

    "jest": {
      "setupTestFrameworkScriptFile": "./tests/setup.js"
    }
    
  2. 然后,您需要在模型中使用mongoose和setup.js文件中的mongoose库进行需求,然后建立与数据库的连接:

    require('../models/yourModel'); //require in any models that you need to use in your tests
    const mongoose = require('mongoose');
    
    mongoose.connect(mongoURI,{useMongoClient: true});
    mongoose.connection.once('open',()=>{}).on('error',(err)=> 
    {console.log(err)});
    
  3. 然后,您可以在测试文件中使用模型来运行或测试猫鼬的任何查询,例如,如果要在测试文件中创建名为Model的模型的记录,则:

    const mongoose = require('mongoose');
    const Model = mongoose.model('Model');
    const newRecord = await new Model({}).save();
    //test newRecord