如何用JavaScript模拟pg?

时间:2015-07-02 10:47:07

标签: javascript node.js postgresql unit-testing

我是模仿概念和javascript编程的新手。我想在javascript程序中模拟pg(postgres模块)。我可以模仿非常简单的场景,但实际上我不会。

这是我的userHandler.js:

var pg = require('pg');
var connectionString = process.env.DATABASE_URL || 'postgres://admin:admin@localhost:5432/mydb';

exports.handlePost = function(req,res){

  var results = [];

  // Grab data from http request
    var adata = [req.body.Username, ..., req.body.FaxNum];  //Ignore for short.

  // Get a Postgres client from the connection pool
  pg.connect(connectionString, function(err, client, done) {

        // SQL Query > Insert Data
        var func_ = 'SELECT Dugong.Users_Add($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)';
        var addUser_ = client.query(func_, adata);

        addUser_.on('error', function(error){
            var data = {success : false, 
                        username : req.body.Username,
                        reason : {errmsg : error.detail,
                                    errid : 'addUser_' }};
            return res.json(data);
        });

        addUser_.on('end',function(result){
            var data = {success : true, username : req.body.Username};
            console.log('Insert record completed');
            return res.json(data);
        });

    // Handle Errors
    if(err) {
      console.log(err);
      return ;
    }
    return;
  });
};

这是我的单元测试文件。 m_users_page.js:

var express = require('express');
var router = express.Router();
var test = require('unit.js');
var mock = require('mock');
var httpMocks = require('node-mocks-http');
var real_users_page = require('../routes/users_page.js');

var b = mock("../routes/userHandler.js", {
    pg: {
        connect: function (connectionString,callback) {
                    if(connectionString === 'postgres://admin:admin@localhost:5432/skorplusdb'){
                        console.log('333');

                        //pseudo object
                        var client = {query : function(func_, adata, cb){
                            cb(null,adata);
                        }};

                        client.on('error', 'test emit the error in my mock unit.');

                        //pseudo done object
                        var done = function(){};
                        callback(null, client, done);

                        return ;
                    }
      }
  }
}, require);

describe('Test with static login', function(){

    it('Test simple login', function(done){
        var request  = httpMocks.createRequest({
        method: 'POST',
        url: '/users',
        body: { Username:"Je", ..., FaxAreaCode:'232'} //Ignore for short
    });

    var response = httpMocks.createResponse();

        b.handlePost(request,response, function(){
            var data = response._getData();
            console.log("7777777777" + data);

            done();
        });
    }); 
});

这是错误:

$ mocha testing/m_users_page.js


  Test with static login
333
    1) Test simple login


  0 passing (7ms)
  1 failing

  1) Test with static login Test simple login:
     TypeError: Object #<Object> has no method 'on'
      at Object.mock.pg.connect (testing/m_users_page.js:22:14)
      at Object.exports.handlePost (routes/userHandler.js:30:6)
      at Context.<anonymous> (testing/m_users_page.js:63:5)

我的问题是:

  1. 在Node + Express + Mock + node-mocks-http中进行单元测试的正确方法是什么?
  2. 如何找到好的文档,我必须阅读。几天后,我开始围绕搜索引擎的结果盘旋。它们太简单了,我无法适应我的问题。

1 个答案:

答案 0 :(得分:0)

首先,请确保您了解 unit 测试和 integration 测试之间的区别。如果要针对实际的db进行测试,即使它具有虚拟数据集,那也是一个集成测试,并且不需要模拟:只需使用虚拟数据连接到数据库即可。

但是假设您想测试您的Web服务器模块,并且想要模拟数据库。首先,将数据库模块作为 parameter 传递,而不是直接要求pg。另外,用自己的类包装postgres接口:

const { Pool } = require('pg');

module.exports = class DatabaseInterop {
  // Connection parameters can be passed to the constructor or the connect method, parameters to
  // DatabaseInterop::connect will override the initial constructor parameters.
  constructor ({
    user,
    password,
    database,
    host,
    logger={log: console.log, err: console.error},
  }) {
    this.logger = logger;
    this._params = {
      user,
      password,
      database,
      host,
    };
  }

  connect (params) {
    const {
      user,
      password,
      database,
      host,
    } = Object.assign({}, this._params, params);

    this._pool = new Pool({
      user,
      password,
      database,
      host,
    });

    ['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
        'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'
    ].forEach(function (sig) {
        process.on(sig, async () => {

          logger.log(`Exiting for ${sig}...`);
          process.exit(0);
        });
    });

    return this;
  }

  async stop () {
    return this._pool.end();
  }

  runQuery (queryString, params=[]) {
    return params.length ? this._pool.query(queryString, params) : this._pool.query(queryString);
  }
};

现在要模拟它,您只需在测试文件中扩展自定义类即可:

const DatabaseInterop = require('/path/to/database_interop.js');
class MockDB extends DatabaseInterop {

    connect () {
      // no-op
    }

    runQuery (qs, ...params) {
      // return whatever
    }

    stop () {
      // noop
    }
}

现在可以进行测试了,您可以注入模拟,实际系统可以注入实际接口。