How to stub Backbone View instantiated within anot

2019-06-25 12:00发布

问题:

I am attempting to write unit tests using Jasmine and Sion but I am struggling to find the equivalent of the following when using RequireJs to load modules:

sinon.stub(window, "MyItemView");

When using RequireJs, I am unable to stub this way as MyItemView is not attached to the window.

The following is an example of when I need stub the MyItemView:

var MyView = Backbone.View.extend({
el: '#myElement',
initialize : function() {
    var that = this;
    this.collection.fetch({
        success : function() {
            that.render();
        }
    });
},

render : function() {
    this.collection.each(this.renderItem);
}

renderItem: function(model){
        var myItemView = new MyItemView({model: model});
        $('#myElement').append(myItemView.render().el);
    },

...

Now, using Jasmine I can test that the innerHtml contains the expected HTML:

it('View should contain correct Html', function(){
            var collectionFetchStub = sinon.stub(this.myCollection, 'fetch').yieldsTo('success', this.myCollection);
            this.view = new MyView({collection: this.myCollection});
            expect(this.view.el.innerHTML).toContain('<li><a href=""> 1 : test </a></li>');

            // Remove Stubs
            collectionFetchStub.restore();
        });

However, this test has a dependency on the rendering of MyItemView, which is not ideal for a unit test. What is the best solution to this problem? I am quite a novice to javascript and a solution to this seems complex.

回答1:

Take a look at this SO on how to stub dependencies with requireJS. There are some solutions. Like testrJs, squireJs or my own little solution. The main idea is to override the requireJs dependency with your spy/stub/mock so you can test only the module.

So in your case you could to stub MyItemView like this:

var el = $("<div>test</div>")
var MyItemView = sinon.stub().returns({render: sinon.stub().returns(el)})

Then you have to inject the MyItemView stub into your require context and you can test the test div was appended to $('#myElement'). This is not ideal, cause all of the DOM stuff but it will work. A better way would be not to render something outside your backbone view. Cause then you can inject a mocked el into the view and just test that the append method of your mock was called.