注入一个angularjs控制器测试的模拟服务

问题描述:

我想测试一个控制器,这取决于我自己建立的服务。我想嘲笑这项服务,因为服务与DOM对话。注入一个angularjs控制器测试的模拟服务

这是我目前的测试:

describe('Player Controllers', function() { 

    beforeEach(function() { 
     this.addMatchers({ 
      toEqualData: function (expected) { 
       return angular.equals(this.actual, expected); 
      } 
     }); 
    }); 

    describe('TestPSPlayerModule', function() { 
     var $httpBackend, scope, ctrl; 

     beforeEach(module('PSPlayerModule')); 

     beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { 
      $httpBackend = _$httpBackend_; 

      scope = $rootScope.$new(); 
      ctrl = $controller(PlayerController, { $scope: scope }); 
     })); 

     it('should request a clip url from the server when clipClicked is called', function() { 
      expect(1).toBe(1); 
     }); 
    }); 

}); 

我的控制器看起来是这样的:

w.PlayerController = function ($scope, $http, $window, speedSlider, $location) { 
    ... 
} 

所以这是我想嘲笑speedSlider。

我有主意,用一个模块我在测试代码创建了一个可以提供伪造的实施速度滑块,所以我增加了以下的test.js文件的顶部:

module('TestPSPlayerModule', []).factory('speedSlider', function() { 
    return = { 
     ... 
    }; 
}); 

,然后列出在beforeEach该模块()调用,而不是具体的一个,但如果我这样做,我得到以下错误:

Injector already created, can not register a module! 

所以我想一定有给我提供了一个更好的办法模拟执行我的一项服务。我可以使用sinon.js作为...

+0

你见过这个文档吗? http://docs.angularjs.org/guide/dev_guide.services.testing_services其中'$ window'被嘲笑。这是一个相当简单的例子,但它可能为您想要做的事提供模板。 – 2012-07-12 22:31:05

+0

@NoahFreitas你提供的链接现在已经死亡 – Stephane 2015-04-11 14:35:53

+1

@StephaneEybert,看起来它已被移动并更新到这里:https://docs.angularjs.org/guide/services#unit-testing – 2015-04-11 18:01:14

确保在您使用模块后,您没有额外的括号。所以module('TestPSPlayer')而不是module('TestPSPlayer',[])

还要确保你不试图做到这一点的注入函数调用内:

这将引发错误:

beforeEach(inject(function(someOtherService) { 
     module('theApp', function($provide) { 
      myMock = {foo: 'bar'}; 
      $provide.value('myService', myServiceMock); 
      someOtherService.doSomething(); 
     }); 
    })); 

这不会:

beforeEach(function() { 
     module('theApp', function($provide) { 
      myMock = {foo: 'bar'}; 
      $provide.value('myService', myServiceMock); 
     }); 

     inject(function(someOtherService) { 
      someOtherService.doSomething(); 
     }); 
    }); 
+0

更多相关imho – davidjnelson 2014-10-11 02:01:25

+7

嵌套'module( )'inject()'里面'不是导致错误的原因。实际上,所有的'module()'调用都必须是_before_'inject()'。 – 2014-11-18 10:15:49

+0

@HermanKan为什么? – tobi 2015-04-14 05:38:25

在我的情况这没有奏效:

beforeEach(module('user')); 
beforeEach(inject(function ($http) { 
})); 

beforeEach(module('community')); 
beforeEach(inject(function ($controller, $rootScope) { 
})); 

我已经改变了这使它的工作:

beforeEach(module('user')); 
beforeEach(module('community')); 

beforeEach(inject(function ($http) { 
})); 
beforeEach(inject(function ($controller, $rootScope) { 
})); 
+0

这解释了应该在所有模块初始化之后调用注入 – 2016-05-31 10:56:20

如果您的提供商不使用全局初始化,您可以使用原来的注射提供商和嘲笑它。在下面的示例中,是您的控制器。

var injectedProviderMock; 

beforeEach(function() { 
    module('myModule'); 
}); 

beforeEach(inject(function (_injected_) { 
    injectedProviderMock = mock(_injected_); 
})); 


var testedProvider; 
beforeEach(inject(function (_testedProvider_) { 
    testedProvider = _testedProvider_; 
})); 

it("return value from injected provider", function() { 
    injectedProviderMock.myFunc.andReturn('testvalue'); 
    var res = testedProvider.executeMyFuncFromInjected(); 
    expect(res).toBe('testvalue'); 
}); 

//mock all provider's methods 
function mock(angularProviderToMock) { 

    for (var i = 0; i < Object.getOwnPropertyNames(angularProviderToMock).length; i++) { 
     spyOn(angularProviderToMock,Object.getOwnPropertyNames(angularProviderToMock)[i]); 
    } 
    return angularProviderToMock; 
}