2016-02-05 208 views
0

我有她的项目,具有以下设置:JavaScript ES6(与Babel一起编译),mocha测试,使用node-mysql和Bluebird Promises的MySql访问。使用sinon mocks设置摩卡测试,使用mysql和bluebird承诺

也许使用蓝鸟与巴贝尔/ ES6已经是我的第一个问题在一起,但让我们解释的情况和问题:

我DBRepository对象:

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在摩卡测试,以兴农的嘲笑我获得以下错误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'); 

    }); 
}); 

也许根本不可能模拟一个promisfyed对象?

有没有在这方面的经验的人?

回答

2

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这样的魔法。相反,保持简单,只需将依赖项中需要测试的方法“存根(stub)”即可。但是,您可以使用“间谍”来检查正在生成的正确SQL,但我会在集成测试中执行此操作。

这有帮助吗?