使用sinon mocks设置摩卡测试,并带有mysql和bluebird承诺

Set up a mocha tests with sinon mocks, with mysql and bluebird promises

本文关键字:mysql 承诺 bluebird mocks sinon 设置 摩卡 测试 使用      更新时间:2023-09-26

我给她准备了一个具有以下设置的项目:JavaScript ES6(用Babel转译),mocha测试,使用node-mysql和Bluebird Promises访问MySql。

也许将 Bluebird 与 Babel/ES6 一起使用已经是我的第一个问题,但让我们解释一下情况和问题:

我的数据库虚拟对象:

let XDate = require('xdate'),
  _ = require('lodash');
const Promise = require("bluebird");
const debug = require('debug')('DBRepository');
class DBRepository {
  constructor(mysqlMock) {
    "use strict";
    this.mysql = mysqlMock;
    if( this.mysql == undefined) {
      debug('init mysql');
      this.mysql = require("mysql");
      Promise.promisifyAll(this.mysql);
      Promise.promisifyAll(require("mysql/lib/Connection").prototype);
      Promise.promisifyAll(require("mysql/lib/Pool").prototype);
    }
    this.config = {
      connectionLimit: 10,
      driver: 'pdo_mysql',
      host: 'my_sql_container',
      port: 3306,
      user: 'root',
      password: '**********',
      testDbName: 'db-name'
    };
    this.pool = this.mysql.createPool(this.config); // <== Here the error is thrown
  }
  getSqlConnection() {
    return this.pool.getConnectionAsync().disposer(function (connection) {
      try {
        connection.release();
      } catch (e) {
        debug('Error on releasing MySQL connection: ' + e);
        debug(e.stack);
      }
    });
  }
  getGoods(queryParams) {
    "use strict";
    if (queryParams === undefined) {
      queryParams = {};
    }
    if (queryParams.rowCount === undefined) {
      queryParams.rowCount = 15;
    }
    let query = "SELECT id, name FROM my_table";
    return Promise.using(this.getSqlConnection(), (conn => {
      debug('query: ' + query);
      return conn.queryAsync(query);
    }));
  }
}

这段代码在我的普通代码中对我来说效果很好,但是当我尝试在摩卡测试中使用 int 时,使用 sinon 进行模拟,我得到以下错误TypeError: this.mysql.createPool is not a function

这是我的测试代码:

let expect = require('chai').expect,
  XDate = require('xdate'),
  _ = require('lodash'),
  sinon = require('sinon'),
  Promise = require('bluebird'),
  toBeMocketMySql = require('mysql');
Promise.promisifyAll(toBeMocketMySql);
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
describe(".inflateOffers(offerPCs, offerGroups)", () => {
  "use strict";
  it('should inflate Offers (with all OfferGroups and a PricingCluster from db rows.', () => {
    let offerPCs = JSON.parse('[... some objects ...]');
    let offerGroups = JSON.parse('[... some objects ...]');
    let mock = sinon.mock(toBeMocketMySql);
    let dbRepo = new DBRepository(mock); // <== Here the error is thrown

    let offers = dbRepo.inflateObjects(offerPCs, offerGroups);
    expect(offers).to.be.an('object')
      .and.to.be.an('array')
      .to.have.length(1);
    expect(offers[0]).to.be.an('object')
      .and.not.to.be.an('array')
      .to.have.property('a')
      .to.have.property('b');
  });
});

也许根本不可能嘲笑一个被捧头的对象?

有人在这方面有经验吗?

DBRepository很难

测试,因为事情太多了 - 为了使测试更容易,你需要分离一些关注点。至少你需要将你的业务逻辑(原始SQL查询)分解成它们自己的类,如下所示:

class GoodsService {
  /**
   * Constructor - inject the database connection into the service.
   *
   * @param {object} db - A db connection
   */
  constructor(db) {
    this.db = db;
  }
  getGoods(queryParams) {
    if (queryParams === undefined) {
      queryParams = {};
    }
    if (queryParams.rowCount === undefined) {
      queryParams.rowCount = 15;
    }
    let query = "SELECT id, name FROM my_table";
    debug('query: ' + query);
    return this.db.queryAsync(query);
  }
}

因此,现在您已将业务逻辑与设置数据库连接器分开。您可以只将完全实例化的数据库连接或存根传递到服务类测试中,如下所示:

let assert = require('assert');
describe('GoodsService', () => {
  it('should return an array', () => {
    let stubbedDb = {
      queryAsync: () => {
        return Promise.resolve([]);
      }
    };
    let instance = new GoodsService(stubbedDb);
    return instance.getGoods()
      .then((result) => {
        assert(Array.isArray(result), 'should return an array of something');
      });
  });
});

这有点过于简单,但你应该明白这个想法。但是,有一些事情需要注意。

你不需要像柴这样的花哨的东西来测试承诺。摩卡已经对此有很好的内置支持。

你不需要像sinon.mock那样使用魔法.相反,保持简单,只是"存根"您需要在依赖项中测试的方法。但是,您可以使用"间谍"来检查正在生成正确的 SQL,但我会在集成测试中这样做。

这有帮助吗?