2016-02-05 103 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,但我會在集成測試中執行此操作。

這有幫助嗎?

相關問題