如何在Nodejs中模拟外部依赖方法回调参数?

时间:2016-08-26 21:41:11

标签: javascript node.js unit-testing mocking

假设我有以下内容:

LIB /模块/ module1.js

function deleteFutureAppointments() {
Appointment.findAll(
{ where: 
    { 
        pro_id, client_id, from_datetime_utc: { 
            $gt: new Date() 
        }
    } 
})
.then((appointments) => {
    if (!appointments) {
        return new Promise((resolve) => resolve());
    }          
    const promises = appointments.map((id) => {
        const appointmentQuery = { where: { client_id } };
        const appointmentSMIQuery = { where: { appointment_id: id.get("appointment_id") } };
        return AppointmentMedia.destroy(appointmentSMIQuery)
        .then((result) => {
            if (result) {
                removeAppointmentMedia.push(id.get("appointment_id"));
            }
            AppointmentService.destroy(appointmentSMIQuery);
        })
        .then(() => IndexAppointmentCalendar.destroy(appointmentSMIQuery))
        .then(() => Appointment.destroy(appointmentQuery));
    });
    return Promise.all(promises);
})
.catch((err) => {
    next(err);
});
}

现在让我们说我在另一个目录中有一组测试,例如的测试/ testModule1.js 即可。从这个文件中,我创建了一个var m2 = require('module2'); module.exports = function(){ return { // ... get: function(cb){ m2.someMethod(params, function(error, data){ if(error){ cb(error) } cb(null, data) }) }, // ... } } 的实例来执行一些测试。

我想从文件 testModule1.js 中模拟module1传递给它的回调函数(不是m2.someMethod函数)的对象。

我调查了Sinon.js,但我无法想办法做到这一点。实际上,我甚至可能吗?

感谢。

2 个答案:

答案 0 :(得分:1)

您可以使用proxyquire之类的内容,但我不喜欢修改内置require

就个人而言,我建议重写代码以使用依赖注入:

module.exports = function(m2){
    return {
        // ...
        get: function(cb){
            m2.someMethod(params, function(error, data){
                if(error){
                    cb(error)
                }

                cb(null, data)
            })
        },
        // ...
    }
}

请注意,我已将m2移动为导出函数中的参数。然后在其他地方(应用程序,主要或其他),你可以这样做:

app.js

var module1Creator = require('module1');
var module2 = require('module2');
var module1 = module1Creator(module2);

然后当你需要测试它时......

testModule1.js

var module1Creator = require('module1');
// inject the "fake" version containing test data, spies, etc
var module2Mocked = require('module2mock');
var module1 = module1Creator(module2mocked);

答案 1 :(得分:0)

我会非常同意改变设计,并且正如@dvlsg所建议的,DI也是我的选择。

但是,我正在进行的项目已经在移动中,并且具有相当大的规模。通过这种改变意味着巨大的人力成本,在这种情况下,可能不值得这样做。

作为一种解决方案,我已经意识到,一旦你执行require('someModule'),就会加载 someModule 并将其存储为单例,在某种情况下全局缓存(我不完全理解这种机制,但我会调查它),如果你从另一个文件中require('someModule')并不重要,你将收到缓存版本。

所以,如果在 lib / modules / module1.js 我做require('module2') module2 被加载并存储在这个缓存中,我可以{{ 1}}并在 tests / testModule1.js 中模拟它。这将反映何时调用 lib / modules / module1.js 中的require('module2')

为此,我使用Sinon.js在测试文件中创建了模拟。

上面的程序实际上解决了我的问题,以一种我不必改变整个设计的方式,我能够进行测试。这就是我发布这个作为答案的原因。但是,我不会在此将此设置为正确的答案,因为正如我之前所说,我不完全理解这种机制并且更改所需的模块不是一个好习惯。

我想看看其他开发者对此有什么看法,如果讨论得到接受,我最终会将其设置为正确。