笑话单元测试+收到未定义

时间:2020-10-12 04:38:13

标签: javascript node.js unit-testing jestjs

我正在使用Jest作为我的单元测试框架。我正在尝试模拟npm的第三部分“请求”并执行了我的测试用例,但是我收到了并且测试失败了

expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: 200

    Number of calls: 0

以下是我的代码:

spec.js

jest.mock('request', () => ({
  post: jest.fn()
}));
const request = require('request');

const mockRequest = (reqData) => {
    return {
      params: reqData.params? reqData.params:{} ,
      body: reqData.body?reqData.body:{},
      headers: reqData.headers?reqData.headers:{}
    };
  };

  const mockResponse = () => {
    const res = {};
    res.status = jest.fn().mockReturnValue(res);
    res.json = jest.fn().mockReturnValue(res);
    res.send = jest.fn().mockReturnValue(res);
    return res;
  };
  describe("Test suite for controller", () => {   
    test("should return true for successful validation",async () => {
request.post.mockResolvedValue({
        "key1":"value1",
        "key2":"value2"
      });
 const req = mockRequest();
      const res = mockResponse();
      const Ctrl = require('../../controllers/ctrl')
      await Ctrl.validate(req, res);
      //const result = await res1.json();
      expect(res.status).toHaveBeenCalledWith(200); 
});
});

Ctrl.js

const request = require('request');
module.exports = {
  async validate(req, res) {
      var postBody = {
        url: url,
        form: body,
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      };      

      await request.post(postBody, function (error, response, body) { 
        if (error) {
           return res.status(200).json({ result: "false" });
        } else {
            return res.status(200).json({ result: "true" });
        }
     });
});
}

请分享您的想法。谢谢。

1 个答案:

答案 0 :(得分:0)

  1. 您无需在await的回调中使用request.post,只需选择其中之一即可。不要一起使用。选择Promise或错误优先的回调来处理异步代码。
  2. 您应该模拟request.post的实现,以便可以在测试用例中获得回调函数。然后,您可以将成功的响应或错误传递给此回调并测试回调的代码逻辑。
  3. 您可以使用mockFn.mockReturnThis()来模拟res对象的链方法。

这是单元测试解决方案:

ctrl.js

const request = require('request');

module.exports = {
  async validate(req, res) {
    var postBody = {
      url: 'url',
      form: req.body,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    };

    request.post(postBody, function(error, response, body) {
      if (error) {
        return res.status(200).json({ result: 'false' });
      } else {
        return res.status(200).json({ result: 'true' });
      }
    });
  },
};

ctrl.spec.js

const request = require('request');
const Ctrl = require('./ctrl');

jest.mock('request', () => ({
  post: jest.fn(),
}));

describe('Test suite for controller', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  test('should return true for successful validation', async () => {
    request.post.mockImplementationOnce((body, callback) => {
      callback(null);
    });
    const req = { body: {} };
    const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
    await Ctrl.validate(req, res);
    expect(request.post).toBeCalledWith(
      {
        url: 'url',
        form: {},
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      },
      expect.any(Function),
    );
    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.json).toBeCalledWith({ result: 'true' });
  });

  test('should handle error for failed validation', async () => {
    const mErr = new Error('network');
    request.post.mockImplementationOnce((body, callback) => {
      callback(mErr);
    });
    const req = { body: {} };
    const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
    await Ctrl.validate(req, res);
    expect(request.post).toBeCalledWith(
      {
        url: 'url',
        form: {},
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      },
      expect.any(Function),
    );
    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.json).toBeCalledWith({ result: 'false' });
  });
});

具有覆盖率报告的单元测试结果:

 PASS  src/stackoverflow/64311760/ctrl.spec.js (16.499s)
  Test suite for controller
    ✓ should return true for successful validation (16ms)
    ✓ should handle error for failed validation (2ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 ctrl.js  |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        19.59s