简体   繁体   中英

Angular Karma Unit Testing Controller Not Injecting Mocked Service Dependency

I have tried various ways of instantiating the mocked service 'listFilterManager' and passing this to the controller. Although the mocked service is created and accessible, when the scope.$digest() is executed, the actual non-mocked service runs instead of the mocked listFilterManager. Even more confusing is that the resourceStore service is properly mocked and injected. Any help would be greatly appreciated.

Relevant code:

    beforeEach(function(){
        module('listModule');
        module(function($provide){
            $provide.factory('resourceStore', function(){
                return {
                    alertsArray: Object.keys(mockData).map(function(key){
                        return mockData[key];
                    })
                };
            });
            $provide.value('listFilterManager',{
                filterList: jasmine.createSpy('filterList').and.callFake(function(input){
                    return input;
                })
            });
        });
    });

    describe('instantiates the Alert List Ctrl', function(){
        var scope, listFilterParams, listFilterManager, resourceStore, tableAccessorDictionaries, AlertListCtrl;
        beforeEach(function(){
            inject(function(_$rootScope_, $controller, _tableAccessorDictionaries_, _listFilterParams_, _resourceStore_, _listFilterManager_){
                scope = _$rootScope_.$new();
                listFilterParams = _listFilterParams_;
                listFilterManager = _listFilterManager_; //this refs the mocked service, but the actual service is the one that is executed.
                var deps = {
                    '$scope': scope,
                    'tableAccessorDictionaries': _tableAccessorDictionaries_,
                    'listFilterManager': _listFilterManager_,
                    'listFilterParams': _listFilterParams_,
                    'resourceStore': _resourceStore_
                };
                AlertListCtrl = $controller('AlertListCtrl', deps);
            });
        });

        it('it should filter the list when a list filter parameter changes', function(){
            expect(listFilterManager.filterList).not.toHaveBeenCalled();
            scope.filterParams.text = 'This is a test query';
            scope.$digest();
            expect(listFilterManager.filterList).toHaveBeenCalled();
        });

    });

So you're saying that 'listFilterManager' is a service but in the beforeEach method, you are providing it as a value. You need to provide it as a factory in order for it to be properly mocked. Replace the following

               $provide.value('listFilterManager',{
            filterList: jasmine.createSpy('filterList').and.callFake(function(input){
                return input;
            })
        });

with:

               $provide.factory('listFilterManager', function () {
                 return {
                   filterList: jasmine.createSpy('filterList').and.callFake(function(input){
                     return input;
                 };
               })
        });

and it should work properly.

After some time I figured it out. The issue was because the function I was testing was called from within an underscore.debounce wrapper. Debounce apparently causes testing issues, as described here . The solution is to redefine _.debounce within the test file as such (credit to the aforementioned post):

_.debounce = function (func) { return function () { func.apply(this, arguments);}; };

Whew, what a frustrating issue, but hopefully this will help someone else in need!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM