Testing named function within a Controller

12,464

Solution 1

In a sense, using functions like that is private, and cannot be accessed from outside the function. Take a look at this link: http://javascript.crockford.com/private.html

Essentially what is said is that have a function/object in javascript, anything with a this. prefix is public, and anything with a var prefix is private.

For Angular, you can definitely have private variables and functions, if not just to lessen the memory usage of the $scope variable. Private functions should be called by your $scope objects to get values to be displayed/used by the user. Try changing it to this:

.controller( 'DummyCtrl', function DummyCtrl($scope){
   var doSomething = function() {
      return "blah";
   };
   $scope.something=doSomething();
})

And then testing the private function with:

describe( 'DummyCtrl', function(){
    var scope = {},
        ctrl = new DummyCtrl(scope);
    it('should do something', function(){
        expect(scope.something).toMatch('blah');
    });
});

Solution 2

The function DummyCtrl you are providing for the controller registration will be used by Angular as a constructor. If you need the controller instance to expose the function doSomething without attaching it to the $scope, you should attach it to this.

Try changing

var something = function(...

to

this.something = function(...

and your test should work.

You can see this approach here: http://jsfiddle.net/yianisn/8P9Mv/. Also have a look at this SO question: How to write testable controllers with private methods in AngularJs?

Share:
12,464
jbenowitz
Author by

jbenowitz

Updated on July 28, 2022

Comments

  • jbenowitz
    jbenowitz almost 2 years

    A newbie Jasmine/Angular question.

    I have a named function within a controller like so:

    .controller( 'DummyCtrl', function DummyCtrl($scope){
       var doSomething = function() {
          return "blah";
       };
    })
    

    I need to test this function, and am trying to by calling the following Jasmine spec:

    describe ('myApp', function(){
      var $scope, $controller;
      var DummyCtrl;
    
      beforeEach(module('myApp'));
    
      describe('controllers', function(){
        beforeEach(inject(function ($controller, $rootScope){
          $scope = $rootScope.$new();
          DummyCtrl = $controller('DummyCtrl', {$scope: $scope});
        }));
    
        describe( 'DummyCtrl', function(){
                var blah;
    
                beforeEach(function(){
                    blah = DummyCtrl.doSomething();
                });
    
                it('should do something', function(){
                    expect(blah).toContain("blah");
                });
        });
      });
    });
    

    Instead of things working out, I result in the following error: TypeError: Object #<DummyCtrl> has no method 'doSomething'. I'm assuming this is something super simple that I'm not understanding.

  • jbenowitz
    jbenowitz about 11 years
    that did the trick. I was hoping I could call these private functions to streamline some unit tests (on $scope functions that call these methods). But I'm sure I can figure out a way to do it using what calls them.
  • Dzung Nguyen
    Dzung Nguyen over 10 years
    this should be marked as the answer. The other one doesn't do the problem fully.