最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Jasmine controller testing, expected spy to have been called - Stack Overflow

programmeradmin2浏览0评论

I have a method defined in AngularJS controller which is called on initialization. I want to test it using Jasmine ("jasmine-core": "^2.3.4", "karma": "^0.12.37"). I follow some tutorials on the Internet and StackOverflow questions, but I cannot find the right answer. Please take a look at this code:

Controller usersAddUserController:

(function () {
    'use strict';

    angular.module('app.users.addUser')
        .controller('usersAddUserController', ['$scope', 'usersAddUserService', function ($scope, usersAddUserService) {

            usersAddUserService.getCountryPhoneCodes().then(function (phoneCodes) {
                $scope.phoneCodes = phoneCodes;
            });

        }]);
}());

Jasmine test:

(function () {

    'use strict';

    describe('usersAddUserControllerUnitTest', function () {
        var scope, deferred, objectUnderTest, mockedAddUserService;

        beforeEach(module('app'));

        beforeEach(inject(function ($rootScope, $q, $controller) {
            scope = $rootScope.$new();

            function emptyPromise() {
                deferred = $q.defer();
                return deferred.promise;
            }

            mockedAddUserService = {
                getCountryPhoneCodes: emptyPromise
            };
                     
            objectUnderTest = $controller('usersAddUserController', {
                $scope: scope,
                usersAddUserService: mockedAddUserService
            });
        }));

        it('should call getCountryPhoneCodes method on init', function () {
            //when            
            spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
            
            deferred.resolve();

            scope.$root.$digest();
            
            //then
            expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
        });

    });
}());

After running the tests, the error message is:

PhantomJS 1.9.8 (Windows 7 0.0.0) usersAddUserControllerUnitTest should call getCountryPhoneCodes method on init FAILED

    Expected spy getCountryPhoneCodes to have been called.

I obviously missing something, but I cannot figure out what it is. Any help will be appreciated.

I have a method defined in AngularJS controller which is called on initialization. I want to test it using Jasmine ("jasmine-core": "^2.3.4", "karma": "^0.12.37"). I follow some tutorials on the Internet and StackOverflow questions, but I cannot find the right answer. Please take a look at this code:

Controller usersAddUserController:

(function () {
    'use strict';

    angular.module('app.users.addUser')
        .controller('usersAddUserController', ['$scope', 'usersAddUserService', function ($scope, usersAddUserService) {

            usersAddUserService.getCountryPhoneCodes().then(function (phoneCodes) {
                $scope.phoneCodes = phoneCodes;
            });

        }]);
}());

Jasmine test:

(function () {

    'use strict';

    describe('usersAddUserControllerUnitTest', function () {
        var scope, deferred, objectUnderTest, mockedAddUserService;

        beforeEach(module('app'));

        beforeEach(inject(function ($rootScope, $q, $controller) {
            scope = $rootScope.$new();

            function emptyPromise() {
                deferred = $q.defer();
                return deferred.promise;
            }

            mockedAddUserService = {
                getCountryPhoneCodes: emptyPromise
            };
                     
            objectUnderTest = $controller('usersAddUserController', {
                $scope: scope,
                usersAddUserService: mockedAddUserService
            });
        }));

        it('should call getCountryPhoneCodes method on init', function () {
            //when            
            spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
            
            deferred.resolve();

            scope.$root.$digest();
            
            //then
            expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
        });

    });
}());

After running the tests, the error message is:

PhantomJS 1.9.8 (Windows 7 0.0.0) usersAddUserControllerUnitTest should call getCountryPhoneCodes method on init FAILED

    Expected spy getCountryPhoneCodes to have been called.

I obviously missing something, but I cannot figure out what it is. Any help will be appreciated.

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jul 3, 2015 at 8:18 Thomas WeglinskiThomas Weglinski 1,0941 gold badge10 silver badges22 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

You are spying on the mock after it has been passed into the instantiated controller.

Try this:

describe('usersAddUserControllerUnitTest', function () {
    var scope, deferred, objectUnderTest, mockedAddUserService, $controller;

    beforeEach(module('app'));

    beforeEach(inject(function ($rootScope, $q, _$controller_) {
        scope = $rootScope.$new();

        function emptyPromise() {
            deferred = $q.defer();
            return deferred.promise;
        }

        mockedAddUserService = {
            getCountryPhoneCodes: emptyPromise
        };

        $controller = _$controller_;
    }));

    function makeController() {    
        objectUnderTest = $controller('usersAddUserController', {
            $scope: scope,
            usersAddUserService: mockedAddUserService
        });
    }

    it('should call getCountryPhoneCodes method on init', function () {
        //when

        spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
        makeController();

        deferred.resolve();

        scope.$root.$digest();

        //then
        expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
    });

});

EDIT Thanks @juunas for noticing the bug in my solution

You can provide the mock like this:

mockedAddUserService = {
    getCountryPhoneCodes: emptyPromise
};


beforeEach(function () {
    module(function ($provide) {
        $provide.value('usersAddUserService', mockedAddUserService);
    });
});

EDIT:

The code should look (as i cannot test it) like this:

(function () {
    'use strict';

    describe('usersAddUserControllerUnitTest', function () {        
        beforeEach(module('app'));

        var emptyPromise = function() {
            var deferred = $q.defer();
            return deferred.promise;
        }

        var mockedAddUserService = {
            getCountryPhoneCodes: emptyPromise
        };

        beforeEach(function () {
            module(function ($provide) {
                $provide.value('usersAddUserService', mockedAddUserService);
            });
        });

        var scope;
        beforeEach(inject(function ($rootScope, $q, $controller) {
            scope = $rootScope.$new();
            $controller('usersAddUserController', {
                $scope: scope
            });
        }));

        it('should call getCountryPhoneCodes method on init', function () {
            spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();

            scope.$root.$digest();

            expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
        });

    });
}());
发布评论

评论列表(0)

  1. 暂无评论