Unit testing function, how to implement call to mock object

realization

I'm writing a unit tests for a controller which has an angular scope function that when called, calls a parse.com framework function that makes a call to the parse server and returns the success parameters or the error code.

How do I go about making a mock of that object for the unit test?

The name of the function in the controller's scope is Parse.User.logIn, and here is the mock object I've made for it so far.

mockParse = {
      User: {
        logIn: function(_userName, _password, callbackObj) {
            callbackObj.success({
              attributes:{
                username: "testuser",
                email: "[email protected]"
              }
            $rootScope.user = _user;
            $rootScope.isLoggedIn = true;
            $state.go('tab.home');
            };
            callbackObj.error({
              err:{
                code: 101
              }
              if (err.code == 101){
                $scope.error.message = "invalid login credentials";
              } else {
                $scope.error.message = "Unexpected error"
              }
            });
        }
      }
    }

Did I do that right? Do I have to make different objects for different callback responses, the error and the success?

When I put it in the test, where do I inject it? Do I place it in the controller, like this?:

    ctrl = $controller("LoginCtrl", {
        $scope: $scope,
        Parse: mockParse
    });

Here's the actual function:

 Parse.User.logIn(($scope.user.username) , $scope.user.password, {
        success: function(_user) {
            console.log('Login Success');
            console.log('user = ' + _user.attributes.username);
            console.log('email = ' + _user.attributes.email);
            $ionicLoading.hide();
            $rootScope.user = _user;
            $rootScope.isLoggedIn = true;
            $state.go('tab.home');
        },
        error: function(user, err) {
            $ionicLoading.hide();
            // The login failed. Check error to see why.
            if (err.code === 101) {
                $scope.error.message = 'Invalid login credentials';
            } else {
                $scope.error.message = 'An unexpected error has ' +
                    'occurred, please try again.';
            }
            console.log('error message on Parse.User.logIn: ' + $scope.error.message);
            $scope.$apply();
        }
    });
Kasper Lewau

Preface: I am not well versed with Parse.js (nor jasmine for that matter)

I would recommend you go and grab sinonjs - super effective and (after some time) easy to use for mocking/stubbing/spying.


Start off by not worrying about the internal implementation of the Parse object, we're only interested in input and output of our dependencies when in a unit testing setting. There should be no reason to stub out a service object in that fine grade detail.


beforeEach

var $scope, Parse, createController;

beforeEach(function () {
  Parse = {};

  module('your_module', function ($provide) {
    // Provide "Parse" as a value in your module.
    $provide.value('Parse', Parse);
  });

  inject(function ($controller, $injector) {
    $scope = $injector.get('$rootScope').$new();
    Parse  = $injector.get('Parse'); // equal to: {} (at this point)

    createController = function () {
      return $controller('LoginCtrl', {
        $scope: $scope,
        Parse:  Parse
      });
    };
  });

  Parse.user = {};
  Parse.user.login = sinon.stub();
});

Parse is now entirely stubbed out. It will be an empty object that is then provided to the module, exposed in our spec, injected into our controller and then decorated with stubbed out methods matching those of the actual implementation (only by name, of course).


expectation(s)

What you should be testing in your controller spec, is not the internal behaviour of the Parse service, but rather that your controller is calling the methods of Parse with the correct parameters.

After that, you can go on to test what your controller, and its associated $scope does in reaction to the Parse.user.login() response.


it's

Note: I am writing these specs with the mocha/chai syntax - adopt the jasmine style as you see fit (not sure how it plays with sinon.js to be quite honest)

it('calls the Parse method', function () {
  createController();

  $scope.login('username', 'pw', angular.noop);

  expect(Parse.user.login).to.have
    .been.calledOnce.and.calledWith('username', 'pw', angular.noop);
});

context('Parse response', function () {
  it('failed', function () {
    Parse.user.login.returns({ status: 'super_error' });

    createController();

    $scope.login('a', 'b', angular.noop);

    expect(/* expect that something on $scope happened? */);
  });

  it('was succesful', function () {
    Parse.user.login.returns({ status: 'great_success', data: {} });

    createController();

    $scope.login('a', 'b', angular.noop);

    expect(/* expect that something on $scope happened? */);
  });
});

That is how I would write it. But - looking at the Parse.user.logIn docs we can see that the method returns a promise.

As such, you will need to take the following steps to effectively stub out the correct behaviour:

var $q; 

// combine this beforeEach block with the first one we wrote. 
beforeEach(function () {
  inject(function ($injector) {
    $q = $injector.get('$q');
  });
});

context('parse.user.login', inject(function ($timeout) {
  var success, error, opts;

  beforeEach(function () {
    success = sinon.stub();
    error   = sinon.stub();

    opts = {
      success: success,
      error:   error
    };
  });

  it('failed', function () {
    Parse.user.logIn.returns($q.reject({ status: 'bad_error' });
    createController();

    $scope.login('a', 'b', opts);
    $timeout.flush(); // Either this, or $rootScope.$digest or .notify(done) to flush the promise.

    expect(error).to.have.been.calledOnce;
  });

  it('was successful', function () {
    Parse.user.logIn.returns($q.when({ status: 'yay!', data: {} });
    createController();

    $scope.login('a', 'b', opts);
    $timeout.flush(); // Either this, or $rootScope.$digest or .notify(done) to flush the promise.

    expect(success).to.have.been.calledOnce;  
  });
}));

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to mock a tornado coroutine function using mock framework for unit testing?

From Dev

How to mock a Android NFC Tag object for unit testing

From Dev

How to Mock RedBean for Unit Testing

From Dev

How to mock a validator for unit testing

From Dev

Unit testing Mock request object MVC .net

From Dev

Python Unit Testing with two mock objects, how to verify call-order?

From Dev

How to mock a buffered file handle for unit testing

From Dev

how to mock an alert in unit testing of angular

From Dev

how do you mock an xml for unit testing?

From Dev

How to mock a CakePHP behavior for unit testing

From Dev

How to provide mock filters for unit testing

From Dev

How to mock data in javascript unit testing ?

From Dev

How to mock LDAP Laravel auth for unit testing

From Dev

how do you mock an xml for unit testing?

From Dev

How to Mock Request object in unit testing asp.net mvc application

From Dev

Unit testing: bypass or mock call to static email helper

From Dev

Should I mock a $this->doSomething() call in unit testing?

From Dev

Inject mock object without java interface for unit testing

From Dev

Setting up Mock IMember Object in Umbraco 7.5.10 for Unit Testing

From Dev

mock up delete function for unit testing in zend framework 2

From Dev

Kotlin Unit Testing for Function Parameter and Object

From Dev

How to mock "document" object for testing in Meteor App?

From Dev

How to unit test this function without mock asserts?

From Dev

how to mock hapi.js reply with sinon for unit testing

From Dev

How to mock render in (Spock, Grails) unit testing Taglib?

From Dev

how to mock $state.params in jasmine unit testing

From Dev

How to mock dependency classes for unit testing with mocha.js?

From Dev

How to Mock/Stub or simply ignore HttpRequest when unit testing

From Dev

How to mock ng-grid when unit testing a controller

Related Related

  1. 1

    How to mock a tornado coroutine function using mock framework for unit testing?

  2. 2

    How to mock a Android NFC Tag object for unit testing

  3. 3

    How to Mock RedBean for Unit Testing

  4. 4

    How to mock a validator for unit testing

  5. 5

    Unit testing Mock request object MVC .net

  6. 6

    Python Unit Testing with two mock objects, how to verify call-order?

  7. 7

    How to mock a buffered file handle for unit testing

  8. 8

    how to mock an alert in unit testing of angular

  9. 9

    how do you mock an xml for unit testing?

  10. 10

    How to mock a CakePHP behavior for unit testing

  11. 11

    How to provide mock filters for unit testing

  12. 12

    How to mock data in javascript unit testing ?

  13. 13

    How to mock LDAP Laravel auth for unit testing

  14. 14

    how do you mock an xml for unit testing?

  15. 15

    How to Mock Request object in unit testing asp.net mvc application

  16. 16

    Unit testing: bypass or mock call to static email helper

  17. 17

    Should I mock a $this->doSomething() call in unit testing?

  18. 18

    Inject mock object without java interface for unit testing

  19. 19

    Setting up Mock IMember Object in Umbraco 7.5.10 for Unit Testing

  20. 20

    mock up delete function for unit testing in zend framework 2

  21. 21

    Kotlin Unit Testing for Function Parameter and Object

  22. 22

    How to mock "document" object for testing in Meteor App?

  23. 23

    How to unit test this function without mock asserts?

  24. 24

    how to mock hapi.js reply with sinon for unit testing

  25. 25

    How to mock render in (Spock, Grails) unit testing Taglib?

  26. 26

    how to mock $state.params in jasmine unit testing

  27. 27

    How to mock dependency classes for unit testing with mocha.js?

  28. 28

    How to Mock/Stub or simply ignore HttpRequest when unit testing

  29. 29

    How to mock ng-grid when unit testing a controller

HotTag

Archive