Есть ли у кого-нибудь пример использования unit test поставщика?
Например:
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
используется в тестах, и я вижу уже настроенный configProvider
, и я могу проверить его как службу. Но как я могу проверить возможность настройки? Или это вообще не нужно?
Ответ 1
У меня был такой же вопрос, и я нашел только рабочее решение в этом ответе Google Group и ссылался на пример скрипта.
Тестирование кода вашего провайдера будет выглядеть примерно так (следуя коду в примере скрипта и тем, что сработало для меня):
describe('Test app.config provider', function () {
var theConfigProvider;
beforeEach(function () {
// Initialize the service provider
// by injecting it to a fake module 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');
});
});
});
Ответ 2
Я использую решение @Mark Gemmill, и он работает хорошо, но затем наткнулся на это немного менее подробное решение, которое устраняет необходимость в поддельном модуле.
fooobar.com/questions/108496/...
Итак,
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');
}));
Или используйте $injector для создания нового экземпляра,
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');
}));
Оба вышеизложенного также позволят вам перенастроить поставщика для каждого отдельного оператора it
в блоке describe
. Но если вам нужно только настроить поставщика один раз для нескольких тестов, вы можете сделать это,
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() {
...
});
Ответ 3
Ответ на @Stephane Catala был особенно полезен, и я использовал его providerGetter, чтобы получить именно то, что я хотел. Возможность заставить провайдера выполнять инициализацию, а затем фактический сервис для проверки правильности работы с различными настройками имеет важное значение. Пример кода:
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;} };
}
}
Спецификация теста Жасмин:
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');
});
});
Ответ 4
вот небольшой помощник, который правильно инкапсулирует выборки поставщиков, следовательно, обеспечивает изолирование между отдельными тестами:
/**
* @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
}
- процесс извлечения провайдера полностью инкапсулирован: нет необходимости в переменных закрытия, которые уменьшают изоляцию между тестами.
- процесс можно разделить на два этапа: шаг "модуль" и шаг "впрыска", которые могут быть соответственно сгруппированы с другими вызовами "модуля" и "впрыска" в unit test.
- Если разделение не требуется, получение провайдера может быть выполнено только одной командой!
Ответ 5
Лично я использую эту технику для издевательства провайдеров, поступающих из внешних библиотек, которые вы могли бы добавить в вспомогательный файл для всех ваших тестов. Разумеется, он может также работать для пользовательского поставщика, как в этом вопросе. Идея состоит в том, чтобы переопределить провайдера в своем модуле, прежде чем он будет вызван приложением
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();
}));
});
});
Ответ 6
Мне нужно было только проверить правильность установки некоторых параметров у поставщика, поэтому я использовал Angular DI для настройки провайдера, когда я инициализировал модуль через module()
.
У меня также были некоторые проблемы с не найденным провайдером, попробовав некоторые из вышеупомянутых решений, чтобы подчеркнуть необходимость альтернативного подхода.
После этого я добавил дополнительные тесты, в которых использовались настройки, чтобы проверить, что они отражают использование нового значения настройки.
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);
});
});
});