簡體   English   中英

使用 Jest 在 Nodejs 中進行單元測試

[英]unit test in Nodejs using Jest

我在控制器中有一個方法,如下所示:

    import { calcu } from '../services/myServices';

    export const getProduct = (req, res, next) => {
      try {
        const { type } = req.params;

        const { id, productCode } = req.body;

        if (!id || !productCode) {
          res.status(400).json({ error: { message: 'Id or productCode is required' } });
        } else {
          switch (type.toUpperCase()) {
            case 'X':
              try {
                const result = calcu(id, productCode);
                res.status(200).json(result);
              } catch (err) {
                res.status(400).json({ error: { message: err.message } });
              }
              break;
            default:
              res.status(400).json({ error: { message: `type ${type} is not support` } });
          }
        }
      } catch (err) {
        next(err);
      }
    };

在這種情況下,這是我的單元測試代碼:

    import { getProduct } from './quotationController';

    describe('Controller', () => {
        let json, res, status;
        test('Should return message error if the id or productCode is missing', () => {
            const req = {
                body: { id: "1111" },
                param: { type: "qqqqq" }
            };
            const next = err => err.message;
            const result = getProduct(req, res, next);
            //expect(result).toBe(undefined);
            expect(result).toEqual({
                code: 400,
                message: 'Id or productCode is required'
            });
        });
    })

運行單元測試代碼時出現錯誤:

結果未定義。

這是單元測試解決方案:

controller.js

import { calcu } from './service';

export const getProduct = (req, res, next) => {
  try {
    const { type } = req.params;
    const { id, productCode } = req.body;

    if (!id || !productCode) {
      res.status(400).json({ error: { message: 'Id or productCode is required' } });
    } else {
      switch (type.toUpperCase()) {
        case 'X':
          try {
            const result = calcu(id, productCode);
            res.status(200).json(result);
          } catch (err) {
            res.status(400).json({ error: { message: err.message } });
          }
          break;
        default:
          res.status(400).json({ error: { message: `type ${type} is not support` } });
      }
    }
  } catch (err) {
    next(err);
  }
};

service.js : (模擬)

export function calcu(id, code) {
  return id + code;
}

controller.test.js :

import { getProduct } from './controller';
import { calcu } from './service';

jest.mock('./service.js', () => ({ calcu: jest.fn() }));

describe('Controller', () => {
  let mRes;
  let mNext;
  beforeEach(() => {
    mRes = { status: jest.fn().mockReturnThis(), json: jest.fn() };
    mNext = jest.fn();
  });
  afterEach(() => {
    jest.resetAllMocks();
  });

  test('Should return message error if the id or productCode is missing', () => {
    const mReq = { body: { id: '1111' }, params: { type: 'qqqqq' } };
    getProduct(mReq, mRes, mNext);
    expect(mRes.status).toBeCalledWith(400);
    expect(mRes.status().json).toBeCalledWith({ error: { message: 'Id or productCode is required' } });
  });

  test('should call next when error happens', () => {
    const mReq = {};
    getProduct(mReq, mRes, mNext);
    expect(mNext).toBeCalledWith(expect.any(Error));
  });

  test('should return message error if type is not support', () => {
    const mReq = { params: { type: 'qqqqq' }, body: { id: '1111', productCode: '22' } };
    getProduct(mReq, mRes, mNext);
    expect(mRes.status).toBeCalledWith(400);
    expect(mRes.status().json).toBeCalledWith({ error: { message: `type ${mReq.params.type} is not support` } });
  });

  test('should return message error if calcu errors', () => {
    const mReq = { params: { type: 'x' }, body: { id: '1111', productCode: '22' } };
    const mError = new Error('calc error');
    calcu.mockImplementationOnce(() => {
      throw mError;
    });
    getProduct(mReq, mRes, mNext);
    expect(calcu).toBeCalledWith('1111', '22');
    expect(mRes.status).toBeCalledWith(400);
    expect(mRes.status().json).toBeCalledWith({ error: { message: mError.message } });
  });

  test('should return correct calc result', () => {
    const mReq = { params: { type: 'x' }, body: { id: '1111', productCode: '22' } };
    calcu.mockReturnValueOnce({ data: 'fake data' });
    getProduct(mReq, mRes, mNext);
    expect(calcu).toBeCalledWith('1111', '22');
    expect(mRes.status).toBeCalledWith(200);
    expect(mRes.status().json).toBeCalledWith({ data: 'fake data' });
  });
});

100% 覆蓋率的單元測試結果:

 PASS  src/stackoverflow/59508494/controller.test.js (7.379s)
  Controller
    ✓ Should return message error if the id or productCode is missing (6ms)
    ✓ should call next when error happens (1ms)
    ✓ should return message error if type is not support (1ms)
    ✓ should return message error if calcu errors (2ms)
    ✓ should return correct calc result (2ms)

---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 controller.js |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        8.731s, estimated 10s

源代碼: https : //github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59508494

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM