使用 Mocha 测试 Express 和 Mongoose

Testing Express and Mongoose with Mocha

我正在尝试使用 Mocha 和 Chai 测试我的 REST API 端点处理程序,该应用程序是使用 Express 和 Mongoose 构建的。我的处理程序主要采用以下形式:

var handler = function (req, res, next) {
    // Process the request, prepare the variables

    // Call a Mongoose function
    Model.operation({'search': 'items'}, function(err, results) {
        // Process the results, send call next(err) if necessary

        // Return the object or objects
        return res.send(results)
    }
}

例如:

auth.getUser = function (req, res, next) {
    // Find the requested user
    User.findById(req.params.id, function (err, user) {
        // If there is an error, cascade down
        if (err) {
            return next(err);
        }
        // If the user was not found, return 404
        else if (!user) {
            return res.status(404).send('The user could not be found');
        }
        // If the user was found
        else {
            // Remove the password
            user = user.toObject();
            delete user.password;

            // If the user is not the authenticated user, remove the email
            if (!(req.isAuthenticated() && (req.user.username === user.username))) {
                delete user.email;
            }

            // Return the user
            return res.send(user);
        }
    });
};

问题在于函数 returns 在调用 Mongoose 方法和测试用例时是这样的:

it('Should create a user', function () {
    auth.createUser(request, response);

    var data = JSON.parse(response._getData());
    data.username.should.equal('some_user');
});

永远不会通过,因为函数在执行任何操作之前 returning。使用 Mockgoose 模拟 Mongoose,使用 Express-Mocks-HTTP 模拟请求和响应对象。

虽然使用 superagent 和其他请求库相当普遍,但我更愿意单独测试功能,而不是测试整个框架。

有没有办法让测试在评估 should 语句之前等待,而无需将我正在测试的代码更改为 return promises?

您应该使用异步版本的测试,方法是向 it 提供一个带有 done 参数的函数。

有关详细信息,请参阅 http://mochajs.org/#asynchronous-code

由于您不想修改代码,一种方法是在测试中使用 setTimeout 等待调用完成。

我会尝试这样的事情:

it('Should create a user', function (done) {
    auth.createUser(request, response);

    setTimeout(function(){
        var data = JSON.parse(response._getData());
        data.username.should.equal('some_user');

        done(); 
     }, 1000); // waiting one second to perform the test
});

(可能有更好的方法)

显然,e​​xpress-mocks-http 前段时间被废弃了,新的代码在 node-mocks-http 下。使用这个新库,可以使用事件执行我要求的操作。它没有记录,但查看代码你可以弄明白。

创建响应对象时必须传递 EventEmitter 对象:

var EventEmitter = require('events').EventEmitter;
var response = NodeMocks.createResponse({eventEmitter: EventEmitter});

然后,在测试中,您向事件 'end' 或 'send' 添加一个侦听器,因为它们都在调用 res.send 时被触发。 'end' 涵盖的内容超过 'send',以防您有 res.send 以外的呼叫(例如,res.status(404).end().

测试看起来像这样:

it('Should return the user after creation', function (done) {
    auth.createUser(request, response);

    response.on('send', function () {
        var data = response._getData();

        data.username.should.equal('someone');
        data.email.should.equal('asdf2@asdf.com');

        done();
    });
});