如何testingAngularJS自定义提供程序

有没有人有如何unit testing提供者的例子?

例如:

config.js

angular.module('app.config', []) .provider('config', function () { var config = { mode: 'distributed', api: 'path/to/api' }; this.mode = function (type) { if (type) { config.isDistributedInstance = type === config.mode; config.isLocalInstance = !config.isDistributedInstance; config.mode = type; return this; } else { return config.mode; } }; this.$get = function () { return config; }; }]); 

app.js

 angular.module('app', ['app.config']) .config(['configProvider', function (configProvider) { configProvider.mode('local'); }]); 

app.js在testing中使用,我看到已经configurationconfigProvider ,我可以testing它作为一项服务。 但是我怎样才能testingconfiguration的能力呢? 或者根本不需要?

我有这个相同的问题,只有在这个谷歌组答案find一个工作解决scheme,这是参考小提琴的例子 。

testing您的提供程序代码看起来像这样(下面的小提琴示例中的代码和什么对我有用 ):

 describe('Test app.config provider', function () { var theConfigProvider; beforeEach(function () { // Initialize the service provider // by injecting it to a fake module's config block var fakeModule = angular.module('test.app.config', function () {}); fakeModule.config( function (configProvider) { theConfigProvider = configProvider; }); // Initialize test.app injector module('app.config', 'test.app.config'); // Kickstart the injectors previously registered // with calls to angular.mock.module inject(function () {}); }); describe('with custom configuration', function () { it('tests the providers internal function', function () { // check sanity expect(theConfigProvider).not.toBeUndefined(); // configure the provider theConfigProvider.mode('local'); // test an instance of the provider for // the custom configuration changes expect(theConfigProvider.$get().mode).toBe('local'); }); }); }); 

我一直在使用@Mark Gemmill的解决scheme,它运行良好,但后来偶然发现了一个稍微不详细的解决scheme,无需伪造模块。

https://stackoverflow.com/a/15828369/1798234

所以,

 var provider; beforeEach(module('app.config', function(theConfigProvider) { provider = theConfigProvider; })) it('tests the providers internal function', inject(function() { provider.mode('local') expect(provider.$get().mode).toBe('local'); })); 

如果您的提供者$ get方法具有依赖关系,则可以手动传递它们,

 var provider; beforeEach(module('app.config', function(theConfigProvider) { provider = theConfigProvider; })) it('tests the providers internal function', inject(function(dependency1, dependency2) { provider.mode('local') expect(provider.$get(dependency1, dependency2).mode).toBe('local'); })); 

或者使用$注入器来创build一个新的实例,

 var provider; beforeEach(module('app.config', function(theConfigProvider) { provider = theConfigProvider; })) it('tests the providers internal function', inject(function($injector) { provider.mode('local') var service = $injector.invoke(provider); expect(service.mode).toBe('local'); })); 

上述两种方式都可以让您在describe块中为每个人声明重新configuration提供程序。 但是,如果您只需要为一次多次testingconfiguration提供程序,则可以执行此操作,

 var service; beforeEach(module('app.config', function(theConfigProvider) { var provider = theConfigProvider; provider.mode('local'); })) beforeEach(inject(function(theConfig){ service = theConfig; })); it('tests the providers internal function', function() { expect(service.mode).toBe('local'); }); it('tests something else on service', function() { ... }); 

@Stephane Catala的回答特别有用,我用他的提供者获取我想要的东西。 能够让提供者进行初始化,然后通过实际服务来validation事情在各种设置下正常工作是非常重要的。 示例代码:

  angular .module('test', []) .provider('info', info); function info() { var nfo = 'nothing'; this.setInfo = function setInfo(s) { nfo = s; }; this.$get = Info; function Info() { return { getInfo: function() {return nfo;} }; } } 

茉莉花testing规范:

  describe("provider test", function() { var infoProvider, info; function providerGetter(moduleName, providerName) { var provider; module(moduleName, [providerName, function(Provider) { provider = Provider; }]); return function() { inject(); return provider; }; // inject calls the above } beforeEach(function() { infoProvider = providerGetter('test', 'infoProvider')(); }); it('should return nothing if not set', function() { inject(function(_info_) { info = _info_; }); expect(info.getInfo()).toEqual('nothing'); }); it('should return the info that was set', function() { infoProvider.setInfo('something'); inject(function(_info_) { info = _info_; }); expect(info.getInfo()).toEqual('something'); }); }); 

这里有一个小小的帮手,可以正确地封装提取提供者,从而确保各个testing之间的隔离:

  /** * @description request a provider by name. * IMPORTANT NOTE: * 1) this function must be called before any calls to 'inject', * because it itself calls 'module'. * 2) the returned function must be called after any calls to 'module', * because it itself calls 'inject'. * @param {string} moduleName * @param {string} providerName * @returns {function} that returns the requested provider by calling 'inject' * usage examples: it('fetches a Provider in a "module" step and an "inject" step', function() { // 'module' step, no calls to 'inject' before this var getProvider = providerGetter('module.containing.provider', 'RequestedProvider'); // 'inject' step, no calls to 'module' after this var requestedProvider = getProvider(); // done! expect(requestedProvider.$get).toBeDefined(); }); * it('also fetches a Provider in a single step', function() { var requestedProvider = providerGetter('module.containing.provider', 'RequestedProvider')(); expect(requestedProvider.$get).toBeDefined(); }); */ function providerGetter(moduleName, providerName) { var provider; module(moduleName, [providerName, function(Provider) { provider = Provider; }]); return function() { inject(); return provider; }; // inject calls the above } 
  • 提取提供程序的过程是完全封装的:不需要closuresvariables来减lesstesting之间的隔离。
  • 这个过程可以分为两步,一个“模块”步骤和一个“注入”步骤,在unit testing中可以分别与其他对“模块”和“注入”的调用进行分组。
  • 如果不需要拆分,检索提供者可以简单地在一个命令中完成!

就我个人而言,我使用这种技术来模拟来自外部库的提供程序,您可以将它们放入所有testing的帮助文件中。 它当然也可以在这个问题上为自定义提供者工作。 这个想法是在应用程序调用它之前,在他的模块中重新定义提供程序

 describe('app', function() { beforeEach(module('app.config', function($provide) { $provide.provider('config', function() { var mode = jasmine.createSpy('config.mode'); this.mode = mode; this.$get = function() { return { mode: mode }; }; }); })); beforeEach(module('app')); describe('.config', function() { it('should call config.mode', inject(function(config) { expect(config.mode).toHaveBeenCalled(); })); }); }); 

我只需要testing某些设置是否在提供程序上正确设置,所以当我通过module()初始化模块时,我使用Angular DI来configuration提供程序。

在尝试了一些上述解决scheme之后,我也遇到了一些提供者没有find的问题,所以强调需要另外一种方法。

之后,我添加了进一步的testing,使用这些设置来检查他们是否反映了使用新的设置值。

 describe("Service: My Service Provider", function () { var myService, DEFAULT_SETTING = 100, NEW_DEFAULT_SETTING = 500; beforeEach(function () { function configurationFn(myServiceProvider) { /* In this case, `myServiceProvider.defaultSetting` is an ES5 * property with only a getter. I have functions to explicitly * set the property values. */ expect(myServiceProvider.defaultSetting).to.equal(DEFAULT_SETTING); myServiceProvider.setDefaultSetting(NEW_DEFAULT_SETTING); expect(myServiceProvider.defaultSetting).to.equal(NEW_DEFAULT_SETTING); } module("app", [ "app.MyServiceProvider", configurationFn ]); function injectionFn(_myService) { myService = _myService; } inject(["app.MyService", injectionFn]); }); describe("#getMyDefaultSetting", function () { it("should test the new setting", function () { var result = myService.getMyDefaultSetting(); expect(result).to.equal(NEW_DEFAULT_SETTING); }); }); });