【问题标题】:Testing Express and Mongoose with Mocha用 Mocha 测试 Express 和 Mongoose
【发布时间】:2015-05-11 19:36:14
【问题描述】:

我正在尝试使用 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);
        }
    });
};

问题在于函数在调用 Mongoose 方法和测试用例时返回,如下所示:

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

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

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

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

有没有办法让测试在评估 should 语句之前等待而不更改我正在测试的代码以返回承诺?

【问题讨论】:

    标签: node.js testing express mongoose mocha.js


    【解决方案1】:

    您应该使用异步版本的测试,通过向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
    });
    

    (可能有更好的办法)

    【讨论】:

    • 我认为这里更好的选择是将 res.send 函数替换为调用 done 的假函数,感谢您的启发。无论如何,我找到了一种使用 node-mocks-http 而不是 express-mocks-http 的方法。我正在写答案。
    • 看看github.com/visionmedia/supertestgithub.com/pgte/nock。 (我用前者测试了一个简单的rest api server)
    • 它们看起来不错,尤其是诺克。 supertest 的问题在于它是用于模拟 HTTP 请求而不是请求对象,测试将通过所有 node/express 堆栈。我更喜欢单元测试来调用特定的函数,看看它们是否独立工作。 Nock 对于调用外部的函数很有用,虽然现在我只有几个。
    【解决方案2】:

    显然,express-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();
        });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-12
      • 2016-06-05
      • 2016-11-15
      • 2015-11-01
      • 2015-06-02
      • 1970-01-01
      • 2016-11-19
      • 1970-01-01
      相关资源
      最近更新 更多