Quelqu'un a-t-il un exemple de test unitaire d'un fournisseur?
Par exemple:
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
utilise dans les tests et je vois déjà configuré configProvider
et je peux le tester en tant que service. Mais comment puis-je tester la possibilité de configurer? Ou il n'a pas besoin du tout?
J'avais cette même question et je n'ai trouvé qu'une solution de travail dans ce réponse du groupe Google et il est référencé exemple de violon .
Tester votre code fournisseur ressemblerait à quelque chose comme ça (en suivant le code dans le exemple de violon et ce qui a fonctionné pour moi):
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');
});
});
});
j'ai utilisé la solution de @Mark Gemmill et cela fonctionne bien, mais je suis ensuite tombé sur cette solution légèrement moins verbeuse qui supprime le besoin d'un faux module.
https://stackoverflow.com/a/15828369/1798234
Donc,
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');
}));
Si la méthode $ get de vos fournisseurs a des dépendances, vous pouvez les transmettre manuellement,
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');
}));
Ou utilisez l'injecteur $ pour créer une nouvelle instance,
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');
}));
Les deux options ci-dessus vous permettent également de reconfigurer le fournisseur pour chaque instruction it
individuelle dans un bloc describe
. Mais si vous n'avez besoin de configurer le fournisseur qu'une seule fois pour plusieurs tests, vous pouvez le faire,
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() {
...
});
La réponse de @Stephane Catala a été particulièrement utile et j'ai utilisé son providerGetter pour obtenir exactement ce que je voulais. Il était important de demander au fournisseur de faire l'initialisation, puis le service réel pour valider que les choses fonctionnent correctement avec divers paramètres. Exemple de code:
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;} };
}
}
Les spécifications du test Jasmine:
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');
});
});
voici un petit assistant qui encapsule correctement les fournisseurs de récupération, garantissant ainsi l'isolement entre les tests individuels:
/**
* @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
}
Personnellement, j'utilise cette technique pour simuler des fournisseurs provenant de bibliothèques externes, que vous pourriez mettre dans un fichier d'aide pour tous vos tests. Cela peut également fonctionner pour un fournisseur personnalisé comme dans cette question bien sûr. L'idée est de redéfinir le fournisseur dans son module avant qu'il ne soit appelé par l'application
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();
}));
});
});
Je n'avais besoin que de tester que certains paramètres étaient correctement définis sur le fournisseur, j'ai donc utilisé Angular DI pour configurer le fournisseur lorsque j'initialisais le module via module()
.
J'ai également eu quelques problèmes avec le fournisseur non trouvé, après avoir essayé certaines des solutions ci-dessus, ce qui a souligné la nécessité d'une approche alternative.
Après cela, j'ai ajouté d'autres tests qui utilisaient les paramètres pour vérifier qu'ils reflétaient l'utilisation de la nouvelle valeur de paramètre.
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);
});
});
});