Ric*_*Lee 2 javascript unit-testing node.js jasmine
我刚开始在茉莉花周围玩耍,但我仍在努力探索/模拟东西,例如,我有一个功能
module.exports = (() => {
....
function getUserInfo(id) {
return new Promise((resolve, reject) => {
redis.getAsync(id).then(result => {
resolve(result)
})
})
}
return { getUserInfo: getUserInfo }
})()
Run Code Online (Sandbox Code Playgroud)
然后我开始编写茉莉花规格
describe('Test user helper', () => {
let userInfo
beforeEach(done => {
userHelper.getUserInfo('userid123')
.then(info => {
userInfo = info
done()
})
})
it('return user info if user is found', () => {
expect(userInfo).toEqual('info of userid 123')
})
})
Run Code Online (Sandbox Code Playgroud)
它运行良好,但是我的问题是如何模拟redis.getAsync调用,这样它才能成为真正的隔离单元测试?
谢谢。
好问题。您可以模拟redis依赖关系,但前提是您稍微重写一下代码以使其更具可测试性。在这里,这意味着将redis设为返回包含的对象的工厂的参数getUserInfo。
当然,这会更改API,调用者现在需要调用export来获取对象。为了解决这个问题,我们可以创建一个包装器模块,该包装器模块使用标准redis对象调用该函数,然后返回结果。然后,我们将实际工厂移至内部模块,该模块仍可以对其进行测试。
这可能是什么样子
user-helper / factory.js
module.exports = redis => {
....
function getUserInfo(id) {
return redis.getAsync(id); // note simplified as new Promise was not needed
}
return {getUserInfo};
};
Run Code Online (Sandbox Code Playgroud)
user-helper / index.js
// this is the wrapper that preserves existing API
module.exports = require('./factory')(redis);
Run Code Online (Sandbox Code Playgroud)
现在进行测试
const userHelperFactory = require('./user-helper/factory');
function createMockRedis() {
const users = [
{userId: 'userid123'},
// etc.
];
return {
getAsync: function (id) {
// Note: I do not know off hand what redis returns, or if it throws,
// if there is no matching record - adjust this to match.
return Promise.resolve(users.find(user => user.userId === id));
}
};
}
describe('Test user helper', () => {
const mockRedis = createMockRedis();
const userHelper = userHelperFactory(mockRedis);
let userInfo;
beforeEach(async done => {
userInfo = await userHelper.getUserInfo('userid123');
done();
});
it('must return user info when a matching user exists', () => {
expect(userInfo).toEqual('info of userid 123');
});
});
Run Code Online (Sandbox Code Playgroud)
注意:正如评论中所讨论的,这只是我对当前情况的偶然处理。您可以使用许多其他设置和约定,但是主要思想只是基于IIFE结果的现有导出,这是一个可靠的模式,我利用NodeJS /index约定来保留现有API。你也可以使用通过双方一个文件,出口module.exports = factory(redis)和module.exports.factory = factory,但这样会,我相信,在较少的NodeJS地道。更广泛的观点是,能够模拟测试,而可测性通常只是参数化。
参数化功能非常强大,其简单性就是为什么使用函数式语言工作的开发人员有时会嘲笑OOP程序员(例如您的确如此),以及我们的秘密咒语,例如“哦光荣的Dependency Injection Container,给我一个instanceofX” :)
不是说OOP或DI搞错了,而是因为可测试性,DI,IOC等只是关于参数化。
有趣的是,如果我们将redis作为模块进行加载,并且如果使用的是可配置的模块加载器(例如SystemJS),则可以通过在测试级别上简单地使用加载器配置来实现。甚至Webpack都可以在某种程度上允许您执行此操作,但是对于NodeJS,您将需要猴子修补Require Function或创建一堆伪造的软件包,这不是很好的选择。
对OP的具体回应
谢谢!这是个好主意,但实际上,当我要测试大量文件时,我需要为每个文件创建一个工厂和index.js,这似乎很奇怪。
您将需要重新构建API表面,并简单地导出消耗代码必须调用的工厂(而不是应用这些工厂的结果)来减轻负担,但是需要权衡取舍,默认实例对消费者很有帮助。
| 归档时间: |
|
| 查看次数: |
1085 次 |
| 最近记录: |