【问题标题】:Testing asynchronous mongodb calls in nodejs with jasmine-node使用 jasmine-node 在 nodejs 中测试异步 mongodb 调用
【发布时间】:2013-05-24 00:59:18
【问题描述】:

我正在使用 jasmine-node 对我的 nodejs 函数运行测试。 作为 nodejs 和 mongodb 的新手,我遇到的第一件事是测试一些数据库调用,但由于 nodejs 的异步特性,我立即陷入困境。

我想做的是:

1) 添加add 函数以向 mongodb 表添加新条目

2) 从该函数接收状态字符串以验证操作的状态

以下是我的规范的代码。在beforeEach 调用中,我初始化了数据库。正如您在实现中看到的那样,它只被实例化一次,因为有一个条件询问它是否已经存在。

var mongo = require('../mongo.js');

describe('mongo', function() {

    // generate a random number in order to test if the written item and the retrieved result match
    var randomNumber = Math.random();

    var item = {
        'cities': {
            'london': randomNumber
        }
    };

    beforeEach(function() {

        mongo.init();

        waitsFor(function() {
            return mongo.getCollection();
        }, "should init the database", 10000);

    });

    it('should return "added" after adding an item to the database', function() {

        var result;

        waitsFor(function() {
            result = mongo.add(item);

            // the result value here is always undefined, 
            // due to the problem i'm having in my implementation
            return result !== undefined;

        }, "adding an item to the database", 10000);

        runs(function() {
            expect(result).toEqual('added');
        });

    }); 

});

现在,对于每个数据库查询,我可以定义一个回调函数,当查询成功运行时执行该函数。我不知道如何实现是将 mongodb 回调的结果返回规范。

这是当前数据库功能的实现:

var mongo  = require('mongodb'),
    Server = mongo.Server,
    Db     = mongo.Db;

var server = new Server('localhost', 27017, {auto_reconnect: true});
var db     = new Db('exampleDb', server);

var collection = false;

// initialize database
var init = function() {
    if (collection === false) {
        db.open(dbOpenHandler);
    }
};

var dbOpenHandler = function(err, db) {
    db.collection('myCollection', dbCollectionHandler);
};

var dbCollectionHandler = function(err, coll) {
    collection = coll;
};

/** returns the current db collection's status
  * @return object db collection
  */
var getCollection = function() {
    return collection !== false;
};

/** Add a new item to the database
  * @param object item to be added
  * @return string status code
  */
var add = function(item) {

    var result = collection.insert( item, {safe: true}, function(err) {

        // !! PROBLEM !!
        // this return call returns the string back to the callee
        // question: how would I return this as the add function's return value
        return 'added';

    });

};

// module's export functions
exports.init = init;
exports.getCollection = getCollection;
exports.add = add;

我也对如何在 mongodb 中测试数据库调用的其他方法持开放态度。 我已经阅读了很多关于这个主题的文章,但没有一篇涵盖我的具体案例。

解决方案

最后,在 JohnnyHK 的回答的帮助下,我设法通过回调使其工作。 查看以下测试用例以了解我所做的:

it('should create a new item', function() {

    var response;

    mongo.add(item, function( err, result) {
        // set result to a local variable
        response = result;
    });

    // wait for async call to be finished
    waitsFor(function() {
        return response !== undefined;
    }, 'should return a status that is not undefined', 1000);

    // run the assertion after response has been set
    runs(function() {
        expect(response).toEqual('added');
    });

)}

【问题讨论】:

  • 看看这个主题的博文:thelambdacalculus.wordpress.com/2011/02/28/5
  • 感谢链接,实际上我已经弄清楚了异步部分,但很高兴知道我不是唯一一个这样做的人。我仍然不明白如何从被调用函数中返回一个值。
  • 不能从依赖于异步结果的异步函数返回值;您必须使用回调将异步结果传递给调用者。
  • 你或其他人能举一个简单的例子来完成这个吗?

标签: node.js mongodb jasmine-node


【解决方案1】:

您现在可以使用 jasmine-node 中的 done 函数更干净地完成此操作:

it('should create a new item', function(done) {
    mongo.add(item, function(error, result) {
        expect(result).toEqual('added');
        done();
    });
});

此测试将等到done() 被异步调用。默认超时时间为 5 秒,之后您的测试将失败。您可以将其更改为 15 秒,如下所示:

it('should create a new item', function(done) {
    mongo.add(item, function(error, result) {
        expect(result).toEqual('added');
        done();
    });
}, 15000);

【讨论】:

  • 很好的答案!谢谢朋友,你让我开心。我花了一上午的时间试图弄清楚如何在mocha 中测试异步函数。事实证明,done 函数也适用于 mocha。
【解决方案2】:

您必须更改您的 add 方法以接受回调参数,以便它可以通过该回调将异步结果传递给调用者:

var add = function(item, callback) {
    collection.insert(item, {safe: true}, function(err) {
        callback(err, 'added');
    });    
};

【讨论】:

  • 谢谢,这对我有用。我将在下面发布我的具体解决方案。
猜你喜欢
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 2015-10-21
相关资源
最近更新 更多