首页 > 解决方案 > 使用 Jest 测试 3rd 方模块中的匿名函数

问题描述

我有一个使用pg( node-postgrelib) 模块的非常简单的模块,我想实现一个 Jest 测试并在pg模拟模块时我想运行它的回调函数来查看console.log运行情况,并且正在调用我的回调

我已经嘲笑了这个模块并试图监视和替换“查询”方法,但它失败并崩溃了,知道我做错了什么吗?

考试科目:

import {Pool} from 'pg';

const pool = new Pool();

module.exports = {
  query: (text, params, callback) => {
    const start = Date.now();

    return pool.query(text, params, (err, res) => {
      const duration = Date.now() - start;
      console.log('executed query', {text, duration, rows: res.rowCount});
      callback(err, res);
    });
  }
};

测试:

jest.mock('pg');

import module from './index';
import { Pool } from 'pg'

beforeAll(() => {
  Pool.mockImplementation(()=>{return jest.fn()});
});


  it('callback is called', () => {
    const cb = (err, res) => true;
    const query = jest.spyOn(Pool, "query");         // <---- Not right, Error
    query.mockImplementation((a,b,c) => c({},{}));
    const resolve = module.query('QUERY TEXT', { a: 1, b: 2}, cb);
    resolve();                                       // <---- Not what I expect
    expect(cb).toBeCalled();
  });
});

抛出的错误:错误:无法监视查询属性,因为它不是函数;给定的未定义

  20 |   it('callback is called', () => {
  21 |     const cb = (err, res) => true;
> 22 |     const query = jest.spyOn(Pool, "query");
     |                        ^
  23 |     query.mockImplementation((a,b,c) => c({},{}));
  24 |     const resolve = module.query('QUERY TEXT', { a: 1, b: 2}, cb);
  25 |     resolve();

  at ModuleMockerClass.spyOn (node_modules/jest-mock/build/index.js:697:15)
  at Object.spyOn (src/db/index.test.js:22:24)

谢谢

标签: javascriptunit-testingjestjsnode-pg-pool

解决方案


这是单元测试解决方案:

index.js

import { Pool } from 'pg';
const pool = new Pool();

module.exports = {
  query: (text, params, callback) => {
    const start = Date.now();

    return pool.query(text, params, (err, res) => {
      const duration = Date.now() - start;
      console.log('executed query', { text, duration, rows: res.rowCount });
      callback(err, res);
    });
  }
};

index.spec.js

import mod from '.';
import { Pool } from 'pg';

jest.mock('pg', () => {
  const mPool = {
    query: jest.fn()
  };
  return { Pool: jest.fn(() => mPool) };
});

const pool = new Pool();

afterEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
});

it('callback is called', done => {
  let queryCallback;
  pool.query.mockImplementation((text, params, callback) => {
    queryCallback = callback;
  });
  const logSpy = jest.spyOn(console, 'log');
  const userCallback = jest.fn();
  mod.query('text', 'params', userCallback);
  const mRes = { rowCount: 1 };
  queryCallback(null, mRes);
  expect(pool.query).toBeCalledWith('text', 'params', queryCallback);
  expect(userCallback).toBeCalledWith(null, mRes);
  expect(logSpy).toBeCalledWith('executed query', { text: 'text', duration: expect.any(Number), rows: 1 });
  done();
});

覆盖率 100% 的单元测试结果:

 PASS  src/stackoverflow/52831401/index.spec.js
  ✓ callback is called (15ms)

  console.log node_modules/jest-mock/build/index.js:860
    executed query { text: 'text', duration: 0, rows: 1 }

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

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


推荐阅读