【问题标题】:How to mock pg in JavaScript?如何在 JavaScript 中模拟 pg?
【发布时间】:2015-09-19 20:34:58
【问题描述】:

我也是模拟概念和 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. 如何通过我必须阅读的好文档找到好的框架。几天后,我开始在搜索引擎的结果周围盘旋。它们太简单了,我无法适应我的问题。

【问题讨论】:

  • 非常很难以一般方式进行,因为查询会更改数据库状态。完全相同的查询文本和参数可以根据其间或同时执行的不相关查询返回不同的结果。
  • @CraigRinger 。谢谢您的答复。现在我知道现在有多难了。到目前为止,我仍在寻找解决方案。
  • 人们通常只是使用一个真实的数据库,其中包含一些测试数据。有时这与他们的生产数据库使用相同的引擎(强烈推荐 IMO)。有时它是像 HSQLDB 或 Derby 这样的小型嵌入式。一般来说,您不能真正期望模拟大型复杂的有状态接口。如果您可以足够简化与它的交互,您可以查看一些模拟框架中的状态模拟支持。不知道您正在使用的模拟框架有任何此类支持。
  • @CraigRinger 。谢谢你的回复。我得到了做测试的命令。其实我自己会用实际的数据库进行测试并在纸上做笔记。

标签: javascript node.js postgresql unit-testing


【解决方案1】:

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

但是假设您想测试您的网络服务器模块,并且您想模拟数据库。首先,将数据库模块作为 参数 传递,而不是直接要求 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
    }
}

现在,对于您的测试,您可以注入模拟,而您的实际系统注入实际接口。

【讨论】:

  • 感谢您的宝贵时间!不幸的是,我现在无法验证答案。因为在那个项目结束后我一直在使用 Django。
猜你喜欢
  • 1970-01-01
  • 2018-05-07
  • 2010-09-16
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2017-06-03
相关资源
最近更新 更多