我非常困惑,希望得到一些帮助。
我认为这段代码的设计不是很糟糕,但是如果发现缺陷,请纠正我。
我似乎无法弄清楚如何测试依赖项上调用new
的函数。这是我熬煮的课程。...去除了不相关的业务逻辑。
MyWrapper.js
const SomeLib = require('SomeLib');
module.exports.MyWrapper = class MyWrapper {
constructor(username, password) {
this._someLib = new SomeLib(username, password);
}
async getFoo(id) {
// other business logic omitted
// which was tested in the MyWrapper.spec.js
return this._someLib.findById(id)
}
async saveFoo(object) {
// other business logic omitted
// which was tested in the MyWrapper.spec.js
return this._someLib.save(object)
}
}
MyApp.js
const MyWrapper = require('MyWrapper');
const process = async (message) => {
const wrapper = new MyWrapper(process.env.username, process.env.password)
// some business logic around the message...omitted
const data = wrapper.getFoo(message.id);
if(data) {
// do stuff with the data
wrapper.saveFoo(data);
} else {
console.log('no data found for message', message);
}
}
module.exports = { process }
MyApp.spec.js
const sut = require('MyApp');
describe('MyApp', function(){
describe('process', function(){
it('should not call save when no data found', async function(){
// how do I prevent 'new MyWrapper(process.env.username, process.env.password)' from being called???
// how do I stub "wrapper.getFoo(message.id)" so I can return "undefined"
const msg = {......};
await sut.process(msg);
// now assert wrapper.getFoo was called
// now assert wrapper.saveFoo was *NOT* called
});
it('should call save when data is found', async function(){
// how do I prevent 'new MyWrapper(process.env.username, process.env.password)' from being called???
// how do I stub "wrapper.getFoo(message.id)" so I can return some JSON
const msg = {......};
await sut.process(msg);
// now assert wrapper.getFoo was called
// now assert wrapper.saveFoo was called
});
});
});
通过以当前的结构形式查看代码,您将无法不调用new MyWrapper
,因为该调用是在您正在调用的函数内部进行的。您可能想要做的是使用依赖注入来传递MyWrapper
的实例。使用DI还可以使您传入Wrapper类的模拟版本,以更好地控制测试。看起来像这样:
// MyApp.js
const MyWrapper = require('MyWrapper');
const wrapper = new MyWrapper(process.env.username, process.env.password);
const process = async (message, wrapper) => {
// some business logic around the message...omitted
const data = wrapper.getFoo(message.id);
if(data) {
// do stuff with the data
wrapper.saveFoo(data);
} else {
console.log('no data found for message', message);
}
}
module.exports = { process }
您可能想在对您的应用程序有意义的其他地方实例化包装器,但是根据您提供的代码,现在可以在测试时传递您自己的Wrapper类的测试版本,如下所示:
// MyApp.spec.js
const sut = require('MyApp');
describe('MyApp', function(){
describe('process', function(){
it('should not call save when no data found', async function(){
// how do I prevent 'new MyWrapper(process.env.username, process.env.password)' from being called???
// how do I stub "wrapper.getFoo(message.id)" so I can return "undefined"
const msg = {......};
const wrapper = new MyWrapper();
await sut.process(msg, wrapper);
// now assert wrapper.getFoo was called
// now assert wrapper.saveFoo was *NOT* called
});
...
});
问题的第二部分涉及使用sinon创建类的存根。 sinon的文档here可能会为您提供如何制作存根并从存根类中返回您自己的值的最佳示例。
希望这会有所帮助!