Sinon猫鼬模型的存根保存实例方法
我正在尝试测试用于使用Mongoose模型保存小部件的服务功能.我想在模型上存入save实例方法,但是我找不到一个好的解决方案.我看到了其他建议,但似乎没有一个完整的建议.
I am trying to test a service function I use to save a widget using a Mongoose model. I want to stub out the save instance method on my model, but I cannot figure out a good solution. I have seen other suggestions, but none seem to be complete.
// widget.js
var mongoose = require('mongoose');
var widgetSchema = mongoose.Schema({
title: {type: String, default: ''}
});
var Widget = mongoose.model('Widget', widgetSchema);
module.exports = Widget;
这是我的服务...
// widgetservice.js
var Widget = require('./widget.js');
var createWidget = function(data, callback) {
var widget = new Widget(data);
widget.save(function(err, doc) {
callback(err, doc);
});
};
我的服务非常简单.它接受一些JSON数据,创建一个新的小部件,然后使用保存"实例方法保存该小部件.然后,它会根据保存调用的结果回叫传递一个err和doc.
My service is very simple. It accepts some JSON data, creates a new widget, and then saves the widget using the "save" instance method. It then calls back passing an err and doc based on the outcome of the save call.
我只想在调用createWidget({title:'Widget A'})...时进行测试...
I only want to test that when I call createWidget({title: 'Widget A'})...
- 通过传递给服务函数的数据调用Widget构造函数一次
- 新创建的小部件对象上的save实例方法被调用一次
- 额外信用:该保存实例方法以err的null值和文档的{title:'Widget A'}的名称来调用.
为了单独进行测试,我可能需要...
In order to test this in isolation, I would probably need to...
- 模拟或存根Widget构造函数,以便它将返回我在测试中创建的模拟widget对象.
- 将模拟小部件对象的保存功能存根,以便我可以控制发生的情况.
我很难弄清楚如何用Sinon来做到这一点.我尝试过SO网页上的几种变体,但是没有运气.
I am having trouble figuring out how to do this with Sinon. I have tried several variations found on the pages of SO with no luck.
注意:
- 我不想将已经构造的模型对象传递给服务,因为我希望服务是唯一知道"猫鼬的东西.
- 我知道这不是最大的交易(仅通过集成或端到端测试来对此进行测试,但是找到一种解决方案会很不错.
感谢您可以提供的任何帮助.
Thanks for any help you can provide.
如果要对此进行测试,这就是我的处理方法,首先要有一种方法将模拟的窗口小部件注入到窗口小部件服务中.我知道有 node-hijack , node-di 之类的东西,他们都有不同的风格,我敢肯定还有更多.选择一个并使用它.
If were to test that, this is how I would approach it, first have a way to inject my mocked widget to the widget-service. I know there's node-hijack, mockery or something like node-di, they all have different styles, I'm sure there's more. Choose one and use it.
一旦确定正确,就可以使用模拟小部件模块创建小部件服务.然后我做类似的事情(这是使用 mocha btw):
Once I get that right, then I create my widget-service with my mock widget module. Then I do something like this(this is using mocha btw):
// Either do this:
saveStub = sinon.stub();
function WidgetMock(data) {
// some mocking stuff
// ...
// Now add my mocked stub.
this.save = saveStub;
}
// or do this:
WidgetMock = require('./mocked-widget');
var saveStub = sinon.stub(WidgetMock.prototype, 'save');
diInject('widget', WidgetMock); // This function doesn't really exists, but it should
// inject your mocked module instead of real one.
beforeEach(function () {
saveStub.reset(); // we do this, so everytime, when we can set the stub only for
// that test, and wouldn't clash with other tests. Don't do it, if you want to set
// the stub only one time for all.
});
after(function () {
saveStub.restore();// Generally you don't need this, but I've seen at times, mocked
// objects clashing with other mocked objects. Make sure you do it when your mock
// object maybe mocked somewhere other than this test case.
});
it('createWidget()', function (done) {
saveStub.yields(null, { someProperty : true }); // Tell your stub to do what you want it to do.
createWidget({}, function (err, result) {
assert(!err);
assert(result.someProperty);
sinon.assert.called(saveStub); // Maybe do something more complicated. You can
// also use sinon.mock instead of stubs if you wanna assert it.
done();
});
});
it('createWidget(badInput)', function (done) {
saveStub.yields(new Error('shhoo'));
createWidget({}, function (err, result) {
assert(err);
done();
});
});
这只是一个示例,我的测试有时会变得更加复杂.碰巧在大多数情况下,我要模拟的后端调用函数(在这里是widget.save)是我希望其行为随每个不同的测试而改变的函数,因此这就是我每次都要重置存根的原因
This is just a sample, my tests sometimes get more complicated. It happens that most of the time, the backend calling function(here it is, widget.save) that I want to mock, is the one that I want it's behavior to change with every different test, so that's why I reset the stub everytime.
这也是做类似事情的另一个示例: https://github.com/mozilla-b2g/gaia/blob/16b7f7c8d313917517ec834dbda05db117ec141c/apps/sms/test/unit/thread_ui_test.js#L1614
Here's also another example for doing similar thing: https://github.com/mozilla-b2g/gaia/blob/16b7f7c8d313917517ec834dbda05db117ec141c/apps/sms/test/unit/thread_ui_test.js#L1614