简体   繁体   中英

How to test function depending on other objects in jasmine unit test

I have a jasmine unit test for a backbone model called Event.

In this model I have a function:

getParticipants: function(){
  new Myappp.Collections.UsersCollection(
    this.get("participations").map(function(participation){
      return participation.get("user");
    });
  );
}

It has 4 dependencies:

  • User model
  • Users collection
  • Participation model
  • Participations collections

I want to test all models in isolation, as it is best practice, but I'm not sure how.

I'm using sinon.js for mocking and stubbing, but don't know how to use it correctly in this situation.

Thanks!

Your method getParticipants is doing a lot of things.. actually 3 things, so I rather will try to make it focus in one only thing: build the Myappp.Collections.UsersCollection . And move all the previous needed calculations to another methods.

And then you'll can focus in the very tricky one: to mock the new call .

I'd do it in 3 phases:

1. Move the Users filter to another place

I suggest to move it to a method in the Myapp.Collections.ParticipationsCollection , then we can just call it from our Event instance like this:

Myapp.Models.Event = 
  Backbone.Model.extend({
    getParticipants: function(){
      var usersArray   = this.get("participations").getUsers();
      var participants = new Myapp.Collections.UsersCollection(usersArray);

      return participants;
    }
  });

Myapp.Collections.ParticipationsCollection = 
  Backbone.Collection.extend({
    getUsers: function(){
      var users = 
        this.map(function(participation){
          return participation.get("user");
        });

      return users;
    }
  });

This way we can easily mocking the getUsers method to test our target method.

2. Wrapping, even more, the Users Array obtaining

I the code example above we still have a complicate chain methods call in the line this.get("participations").getUsers() we can move it to a custom method also easy to mock:

We finish with something like this:

Myapp.Models.Event = 
  Backbone.Model.extend({
    getParticipants: function(){
      var usersArray   = this.getUsersArray();
      var participants = new Myapp.Collections.UsersCollection( usersArray );

      return participants;
    },

    getUsersArray: function(){
      return this.get("participations").getUsers();
    }
  });

3. Test the Collection initialization

Now we have to focus in mocking the Collection Myapp.Collections.UsersCollection and check that our method in initializing and entity of this Collection with the proper params.

The proper params are the result of the method Event.getUsersArray() and now we can easily mock it.

Sinon has an especial expectation to check if a method has been called with new ..

My Jasmine/Sinon approach to this is not really accurate due I'm not testing that the method is returning the new Collection, I hope someone can come with a better implementation:

describe("Event", function() {
  beforeEach(function(){
    testModel = new Myapp.Models.Event();
  });

  it("getParticipants returns proper Collection", function() {
    var usersCollectionSpy = sinon.spy( Myapp.Collections, "UsersCollection" );

    var getUsersArrayMock = sinon.stub(testModel, "getUsersArray");
    getUsersArrayMock.returns( "usersArray" );

    testModel.getParticipants();

    expect( usersCollectionSpy.calledWith( "usersArray" ) ).toBeTruthy();
    expect( usersCollectionSpy.calledWithNew() ).toBeTruthy();
  });
});

Check the jsFiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM