javascript - Come risolvo una promise in un test unitario AngularJS
Sto usando la configurazione base di karma/jasmine per testare il mio codice Angular. Ecco il mio test:
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
describe('main controller', function() {
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
beforeEach(inject(function($controller, $rootScope, $q) {
scope = $rootScope.$new();
$controllerConstructor = $controller;
q = $q;
mockSuperheroData = {
getSuperheroes: function() {
deferred = q.defer();
return deferred.promise;
}
};
ctr = $controllerConstructor('MainCtrl', {$scope: scope, $location: {}, superheroService: mockSuperheroData, keys: {}});
}));
it('should set the result of getResource to scope.heroes', function() {
scope.getHeroes();
expect(scope.heroes).toBe(100);
});
}
scope.getHeroes() chiama mockSuperheroData.getSuperheroes() che restituisce una promessa. Come posso forzare la promessa a restituire ciò che voglio nel test unitario? Dove posso agganciarmi alla promessa per fare il mock del suo risultato?
Risposta n. 1
Come faccio a forzare la promessa a restituire ciò che voglio nel test unitario?
Fondamentalmente dovrai chiamare resolve sul Deferred:
deferred.resolve(100);
Puoi mettere quello direttamente prima del return deferred.promise oppure in un setTimeout asincrono.
Risposta n. 2
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q;
describe('main controller', function() {
var $controllerConstructor, ctr, mockSuperheroData, scope, deferred, q, rootScope;
beforeEach(inject(function($controller, $rootScope, $q) {
scope = $rootScope.$new();
$controllerConstructor = $controller;
q = $q;
rootScope = $rootScope;
mockSuperheroData = {
getSuperheroes: function() {
deferred = q.defer();
return deferred.promise;
}
};
ctr = $controllerConstructor('MainCtrl', {$scope: scope, $location: {}, superheroService: mockSuperheroData, keys: {}});
}));
it('should set the result of getResource to scope.heroes', function() {
scope.getHeroes();
deferred.resolve(100);
rootScope.$apply();
expect(scope.heroes).toBe(100);
});
});
Va menzionato che, poiché $q è integrato con $rootScope, non solo è necessario risolvere l'oggetto deferred, ma è anche necessario propagare le modifiche chiamando $rootScope.$apply.
Ho scritto un blog su come prendere in giro le promesse di Angular su projectpoppycock
e ho scritto un esempio funzionante, con test, su plunkr
Mi piace davvero il modo in cui stai iniettando il servizio mock come dipendenza del controller usando il servizio $controller, potrei dover rivedere il mio modo di farlo. Il tuo modo è migliore :) Grazie!
