首页 > 解决方案 > JEST Mongoose POST 测试失败 - toBeCalledWith()

问题描述

我正在尝试通过在我当前的 OKR API 上实现它来学习 JEST - 但我似乎无法让这个 POST 请求验证工作......我想知道你们中的任何一个了不起的人可以提供帮助。我对此很陌生,对调试 JEST 问题的策略并不完全清楚。感谢所有和任何帮助:)

笑话代码:

    const objectiveController = require('../../controller/objectives-controller');
    const ObjectiveModel = require('../../Models/Objectives')
    const httpMocks = require('node-mocks-http')
    const newObjective = require('../mock/objectiveMockData.json')

    ObjectiveModel.create = jest.fn()
    let req, res, next;
    beforeEach(() => {
        req = httpMocks.createRequest();
        res = httpMocks.createResponse();
        next = null

    })

 describe('objectiveController.postObjective', () => {
    it('Should have a post function', () => {
        expect(typeof objectiveController.postObjective).toBe('function')
    })
    it('Should call ObjectiveModel.create', () => {
        req.body = newObjective
        ObjectiveModel.create(req, res, next);
        expect(ObjectiveModel.create).toBeCalledWith(req.body);
    })
})

这是控制器逻辑:

exports.postObjective = async (req,res,next) => {
    req.body.user = req.user.id

    try {
        const objective = await Objectives.create(req.body)
        res.status(201).json({
            success: true,
            data: objective
    })
    } catch (err) {
        res.status(400).json({
            success: false
        })
    }
}

这是模拟 JSON:

{
    "name": "____MOCK POST REQUEST DATA TITLE",
    "description": "___MOCK POST REQUEST DATA DESCRIPTION",
    "atRisk": false,
    "user": "60e2f4d5a85e1c5ba5fc995e"
}

而且,这里是猫鼬模型:

const mongoose = require('mongoose');
const slugify = require('slugify')
const chalk = require('chalk')


const ObjectiveSchema = new mongoose.Schema({
        name: {
          type: String,
          required: [true, 'Please add a name'],
          unique: true,
          trim: true,
          maxlength: [75, 'Name can not be more than 75 characters']
        },
        slug: String,
        description: {
          type: String,
          required: [true, 'Please add a description'],
          maxlength: [500, 'Description can not be more than 500 characters']
        },
        atRisk: {
          type: Boolean,
          default: false
        },
        user: {
          type: mongoose.Schema.ObjectId,
          ref: 'User',
          required: false
        }
      },
      {
        toJSON: { virtuals: true },
        toObject: { virtuals: true }
      }
)


// cascading delete - if we delete the objective - we should delete the 
ObjectiveSchema.pre('remove', async function(next) {
  console.log(`courses being removed from objective: ${this._id}`)
  await this.model('KeyResult').deleteMany({
    objective: this._id
  })
})

//? Create a SLUG pre-save
ObjectiveSchema.pre('save', function(next) {
    this.slug = slugify(this.name, {
      lower: true,
    })
    next()
  })

module.exports = mongoose.model('Objectives', ObjectiveSchema);

这是运行测试的极长输出

 FAIL  tests/unit/objective.controller.test.js
  objectiveController.deleteObjective
    ✓ Should have a delete function (2 ms)
  objectiveController.getObjectives
    ✓ Should be a get function
  objectiveController.postObjective
    ✓ Should have a post function (1 ms)
    ✕ Should call ObjectiveModel.create (6 ms)
  objectiveController.getSingleObjective
    ✓ Should have a get function
  objectiveController.updateObjective
    ✓ Should have a put function (1 ms)

  ● objectiveController.postObjective › Should call ObjectiveModel.create

    expect(jest.fn()).toBeCalledWith(...expected)

    - Expected
    + Received

    - Object {
    + EventEmitter {
    +   "_addBody": [Function anonymous],
    +   "_events": Object {},
    +   "_eventsCount": 0,
    +   "_maxListeners": undefined,
    +   "_setBaseUrl": [Function anonymous],
    +   "_setBody": [Function anonymous],
    +   "_setCookiesVariable": [Function anonymous],
    +   "_setFilesVariable": [Function anonymous],
    +   "_setHeadersVariable": [Function anonymous],
    +   "_setMethod": [Function anonymous],
    +   "_setOriginalUrl": [Function anonymous],
    +   "_setParameter": [Function anonymous],
    +   "_setSessionVariable": [Function anonymous],
    +   "_setSignedCookiesVariable": [Function anonymous],
    +   "_setURL": [Function anonymous],
    +   "accepts": [Function anonymous],
    +   "acceptsCharsets": [Function anonymous],
    +   "acceptsEncodings": [Function anonymous],
    +   "acceptsLanguages": [Function anonymous],
    +   "baseUrl": "",
    +   "body": Object {
          "atRisk": false,
          "description": "___MOCK POST REQUEST DATA DESCRIPTION",
          "name": "____MOCK POST REQUEST DATA TITLE",
          "user": "60e2f4d5a85e1c5ba5fc995e",
    +   },
    +   "cookies": Object {},
    +   "files": Object {},
    +   "get": [Function anonymous],
    +   "header": [Function anonymous],
    +   "headers": Object {},
    +   "hostname": "",
    +   "is": [Function anonymous],
    +   "method": "GET",
    +   "originalUrl": "",
    +   "param": [Function anonymous],
    +   "params": Object {},
    +   "path": "",
    +   "query": Object {},
    +   "range": [Function anonymous],
    +   "send": [Function anonymous],
    +   "socket": Object {},
    +   "subdomains": Array [],
    +   "url": "",
    +   Symbol(kCapture): false,
      },
    + {"_getBuffer": [Function anonymous], "_getChunks": [Function anonymous], "_getData": [Function anonymous], "_getHeaders": [Function anonymous], "_getJSONData": [Function anonymous], "_getLocals": [Function anonymous], "_getRedirectUrl": [Function anonymous], "_getRenderData": [Function anonymous], "_getRenderView": [Function anonymous], "_getStatusCode": [Function anonymous], "_getStatusMessage": [Function anonymous], "_headers": {}, "_isDataLengthValid": [Function anonymous], "_isEndCalled": [Function anonymous], "_isJSON": [Function anonymous], "_isUTF8": [Function anonymous], "append": [Function append], "clearCookie": [Function anonymous], "contentType": [Function anonymous], "cookie": [Function anonymous], "cookies": {}, "destroy": [Function anonymous], "destroySoon": [Function anonymous], "end": [Function anonymous], "finished": false, "format": [Function anonymous], "get": [Function anonymous], "getEncoding": [Function anonymous], "getHeader": [Function anonymous], "getHeaderNames": [Function anonymous], "getHeaders": [Function anonymous], "hasHeader": [Function anonymous], "header": [Function header], "headersSent": false, "json": [Function anonymous], "jsonp": [Function anonymous], "locals": {}, "location": [Function anonymous], "redirect": [Function anonymous], "removeHeader": [Function anonymous], "render": [Function anonymous], "send": [Function anonymous], "sendStatus": [Function sendStatus], "set": [Function header], "setEncoding": [Function anonymous], "setHeader": [Function anonymous], "status": [Function anonymous], "statusCode": 200, "statusMessage": "OK", "type": [Function anonymous], "vary": [Function anonymous], "writableEnded": false, "writableFinished": false, "write": [Function anonymous], "writeHead": [Function anonymous]},
    + null,

    Number of calls: 1

      45 |         req.body = newObjective
      46 |         ObjectiveModel.create(req, res, next);
    > 47 |         expect(ObjectiveModel.create).toBeCalledWith(req.body);
         |                                       ^
      48 |     })
      49 |     it('Should return a 201', () => {
      50 |

      at Object.<anonymous> (tests/unit/objective.controller.test.js:47:39)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 6 passed, 7 total
Snapshots:   0 total
Time:        1.466 s, estimated 2 s
Ran all test suites.

标签: node.jsexpressmongoosejestjstdd

解决方案


您没有调用控制器方法postObjective

    it('Should call ObjectiveModel.create', async () => {
        req.body = newObjective;
    
        await objectiveController.postObjective(req, res, next);

        expect(ObjectiveModel.create).toBeCalledWith(req.body);
    })

我认为您还需要模拟'../../Models/Objectives'模块,因此我认为您需要将其放在测试之前: jest.mock('../../Models/Objectives')

并删除该ObjectiveModel.create = jest.fn()


推荐阅读