1

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});

2 Answers 2

1

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
});
Sign up to request clarification or add additional context in comments.

6 Comments

var scope={} is defined out and we are passing scope as a parameter to PhoneListCtrl. So it will become a local variable for that controller.How does it point to the var scope ={} outside. I know something else is going on here and I am thinking in a totally wrong way. Please guide.
Your controller is defined as app.controller('PhoneListCtrl', function($scope) { ... }). This $scope argument is injected by angular. In your test, instead of creating the scope and injecting it, angular takes the one you pass as argument and injects it.
But the scope will be local to that function how is it changing the var scope ={} defined outside.
Angular passes references to objects as argument. So the test has a reference to a scope object, and angular passes a reference to this scope object to the controller. The test and the controller thus both have their own reference to the same scope object. That's fundamental JavaScript stuff. You should learn about objects and variables in JavaScript before using Angular.
This is what I am not understanding.Can you please add an example for this javascript concept to the answer.Thanks.
|
1

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.

2 Comments

Seems to be better syntax but it is not working.Please check.
Your version works when I am using this.phones without injecting $scope in PhoneListCtrl. Please correct me if I am wrong.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.