roshan
roshan

Reputation: 2510

Unit testing controllers in angularJS

I am having a hard time understanding unit tests in angularJs. I have just started with unit tests and the syntax seems weird to me. Below is the code for testing a controller :

describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){

    beforeEach(module('phonecatApp'));

    it('should create "phones" model with 3 phones',
    inject(function($controller) {
      var scope = {},
      ctrl = $controller('PhoneListCtrl', {$scope:scope});

      expect(scope.phones.length).toBe(3);
    }));

  });
});

What I can understand from this syntax is that before each it block phonecatApp is initialised and that $controller service is used to get an instance of PhoneListCtrl controller.

However I am not able to understand the scope thing here. Can someone elaborate on whats behind getting the scope of the controller on this line.

ctrl = $controller('PhoneListCtrl', {$scope:scope});

Upvotes: 1

Views: 287

Answers (2)

Pranay Dutta
Pranay Dutta

Reputation: 2591

It's not necessary to inject the scope, you can directly use the instance of controller to call the controller's functions and objects.In your example you can use like below, this will give the same result set as yours

describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){

     beforeEach(module('phonecatApp'));

       it('should create "phones" model with 3 phones',
           inject(function($controller) {

      var ctrl = $controller('PhoneListCtrl');

  expect(ctrl.phones.length).toBe(3);
  }));

  });
});

and for you information each time the controller is instantiated it is bound to a $scope variable which is derived from $rootScope (i.e: child of rootscope). So you need to pass the $scope to grab the instance of controller and I am doing same thing in above example.

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691655

Normally, at runtime, angular creates a scope and injects it into the controller function to instantiate it. In your unit test, you instead want to create the scope by yourself and pass it to the controller function, in order to be able to see if it indeed has 3 phones after construction (for example).

You might also want to inject mock services instead of the real ones into your controller. That's what the array of objects allows in

$controller('PhoneListCtrl', {$scope:scope});

It tells angular: create an instance of the controller named 'PhoneListCtrl', but instead of creating and injecting a scope, use the one I give you.

If your controller depended on a service 'phoneService', and you wanted to inject a mock phoneService, you could do

var mockPhoneService = ...;
$controller('PhoneListCtrl', { 
    $scope: scope,
    phoneService: mockPhoneService
});

Upvotes: 1

Related Questions