如何使用sinon和mocha在MySQL查询节点上模拟Promisify调用?

2022-06-17 00:00:00 node.js mysql stub sinon mocha.js

这是我使用MySQL的代码-

import * as mysql from 'mysql';
import {promisify} from 'util';


 const connectionParams:any = {
     /* set as environment variables */
     host: host,
     user: user,
     password: password,
     port: parseInt(port)
 };
 var connection:any;
 const getRecords = async (inputValue: string) => {

//validate inputValue

const userIds: string[] = [];
logger.info("Creating mysql connection");
try {
    connection = mysql.createConnection(connectionParams);
    const query = promisify(connection.query).bind(connection);
    const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue] });
    if (queryResult) {
        queryResult.forEach((row) => {
            userIds.push(row.userid);
        });
    }
} catch (error) {
    logger.info(error);
    // console.log(error);
    throw new Error('Could not retrieve user IDs');
} finally {
    connection.end();
}
return userIds;
 };

这是我的测试-

it('should return a list of records when right inputs are given', async() => {
        sinon.stub(process, 'env').value({
            'database': 'TESTDB'
        });
        let dummyArray = [{ userid: 'xyz' }];
        let createConnection = {
            connect: function(connectionParams: any) {
                return Promise.resolve()
            },
            query : sinon.stub().withArgs({}).callsFake(function (...args): Promise<Object>{
                const dummyArray = [{ userid: 'xyz' }];
                return new Promise(function(resolve){resolve(dummyArray)});
            }),
            end: function() {}
        };
        let mySqlStub = {
            createConnection: sinon.stub().returns(createConnection)
        };
        const dbops = proxyquire('../../lib/dbops', {'mysql': mySqlStub}).default;
        expect(await dbops.getUserIds('Delete')).to.deep.equal(['xyz']);
    });

如何编写查询的FAKE函数?

查询:sinon.stub().with Args({}).alls sFake(Function(...args): 承诺{ 常量虚拟数组=[{userid:‘XYZ’}]; 返回新的Promise(function(resolve){resolve(dummyArray)}); })

这对我不起作用。我怎么才能让它起作用呢?我无法让存根函数在Main函数中解析和返回预期的值。查询只是挂起,并在超时后抛出错误。存根中的";matchingfakes";方法中出现错误。


解决方案

proxyquire用于截断模块或包的独立函数导出。由于mysql是一个对象,您可以通过sinon.stub(obj, 'method')来存根它的方法。您不需要使用Useproxyquire包。

即使您使用util.promisify为NodeJS错误优先回调方法(mysql.query(sql, callback),回调签名为function (error, results, ...args): void)生成Promise版本。您需要使用.callsFake()为此方法创建模拟实现,并通过调用其回调来触发Promise版本。

并且,您应该在清除环境变量之后import该函数。因为当您导入./dbops模块时,模块作用域中的代码将立即执行,此时,环境变量不会被存根。

例如

dbops.ts

import mysql from 'mysql';
import { promisify } from 'util';

const connectionParams: any = {
  host: process.env.HOST,
  user: process.env.USER,
  password: process.env.PASSWORD,
  port: parseInt(process.env.PORT || '3306'),
};
var connection: any;

const getRecords = async (inputValue: string) => {
  const sqlQuery = 'SELECT * FROM tests';
  const value1 = '';
  const userIds: string[] = [];
  console.info('Creating mysql connection');
  try {
    connection = mysql.createConnection(connectionParams);
    const query = promisify(connection.query).bind(connection);
    const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue });
    if (queryResult) {
      queryResult.forEach((row) => {
        userIds.push(row.userid);
      });
    }
  } catch (error) {
    console.info(error);
    throw new Error('Could not retrieve user IDs');
  } finally {
    connection.end();
  }
  return userIds;
};

export { getRecords };

dbops.test.ts

import sinon from 'sinon';
import mysql from 'mysql';

describe('69702002', () => {
  it('should return a list of records when right inputs are given', async () => {
    sinon.stub(process, 'env').value({
      HOST: '127.0.0.1',
      USER: 'testuser',
      PASSWORD: 'testpwd',
      PORT: '3306',
    });
    const { getRecords } = await import('./dbops');
    const dummyArray = [{ userid: 'xyz' }];

    let connectionStub = {
      query: sinon.stub().callsFake((sql, callback) => {
        callback(null, dummyArray);
      }),
      end: sinon.stub(),
    };
    sinon.stub(mysql, 'createConnection').returns(connectionStub);
    const actual = await getRecords('test input');
    sinon.assert.match(actual, ['xyz']);
    sinon.assert.calledWithExactly(mysql.createConnection, {
      host: '127.0.0.1',
      user: 'testuser',
      password: 'testpwd',
      port: 3306,
    });
    sinon.assert.calledOnce(connectionStub.end);
  });
});

测试结果:

 69702002
Creating mysql connection
    ✓ should return a list of records when right inputs are given (945ms)


  1 passing (952ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   90.48 |       50 |     100 |      90 |                   
 dbops.ts |   90.48 |       50 |     100 |      90 | 27-28             
----------|---------|----------|---------|---------|-------------------

相关文章