Tengo myServiceese uso myOtherService, que hace una llamada remota, devolviendo la promesa:
angular.module('app.myService', ['app.myOtherService'])
.factory('myService', [
myOtherService,
function(myOtherService) {
function makeRemoteCall() {
return myOtherService.makeRemoteCallReturningPromise();
}
return {
makeRemoteCall: makeRemoteCall
};
}
])
Para hacer una prueba unitaria myService, necesito burlarme myOtherService, de modo que su makeRemoteCallReturningPromisemétodo devuelva una promesa. Así es como lo hago:
describe('Testing remote call returning promise', function() {
var myService;
var myOtherServiceMock = {};
beforeEach(module('app.myService'));
// I have to inject mock when calling module(),
// and module() should come before any inject()
beforeEach(module(function ($provide) {
$provide.value('myOtherService', myOtherServiceMock);
}));
// However, in order to properly construct my mock
// I need $q, which can give me a promise
beforeEach(inject(function(_myService_, $q){
myService = _myService_;
myOtherServiceMock = {
makeRemoteCallReturningPromise: function() {
var deferred = $q.defer();
deferred.resolve('Remote call result');
return deferred.promise;
}
};
}
// Here the value of myOtherServiceMock is not
// updated, and it is still {}
it('can do remote call', inject(function() {
myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
.then(function() {
console.log('Success');
});
}));
Como puede ver en lo anterior, la definición de mi simulacro depende de $qqué debo cargar usando inject(). Además, inyectar el simulacro debería estar sucediendo en module(), lo que debería venir antes inject(). Sin embargo, el valor del simulacro no se actualiza una vez que lo cambio.
¿Cuál es la forma apropiada de hacer esto?
javascript
angularjs
unit-testing
mocking
jasmine
Georgii Oleinikov
fuente
fuente

myService.makeRemoteCall()? Si es así, el problema esmyServiceno tenermakeRemoteCallnada que ver con su burlamyOtherService.Respuestas:
No estoy seguro de por qué la forma en que lo hiciste no funciona, pero generalmente lo hago con la
spyOnfunción. Algo como esto:También recuerde que usted tendrá que hacer una
$digestllamada a lathenfunción a ser llamada. Consulte la sección Pruebas de la documentación de $ q .------EDITAR------
Después de mirar más de cerca lo que estás haciendo, creo que veo el problema en tu código. En el
beforeEach, está configurandomyOtherServiceMockun objeto completamente nuevo. El$providenunca verá esta referencia. Solo necesita actualizar la referencia existente:fuente
andCallFakeusted puede usarandReturnValue(deferred.promise)(oand.returnValue(deferred.promise)en Jasmine 2.0+). Necesita definirdeferredantes de llamarspyOn, por supuesto.$digesten este caso cuando no tiene acceso al alcance?$rootScopey llama$digesta eso.$q.when()codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrongTambién podemos escribir la implementación de la promesa de devolución de jazmín directamente por espía.
Para Jasmine 2:
(copiado de los comentarios, gracias a ccnokes)
fuente
spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue($q.when({}));acabo de matar media hora averiguando eso.fuente
Puede usar una biblioteca de stubbing como sinon para burlarse de su servicio. Luego puede devolver $ q.when () como su promesa. Si el valor de su objeto de alcance proviene del resultado de la promesa, deberá llamar a scope. $ Root. $ Digest ().
fuente
$rootScope.$digest()que se resuelva la promesautilizando
sinon:Conocido eso,
httpPromisepuede ser:fuente
Honestamente ... vas a hacer esto de manera incorrecta confiando en inyectar para burlarse de un servicio en lugar de un módulo. Además, llamar a inyectar en beforeEach es un antipatrón, ya que dificulta la burla por prueba.
Así es como haría esto ...
Ahora, cuando inyecte su servicio, tendrá un método de uso burlado correctamente.
fuente
Encontré esa útil función de servicio de apuñalamiento como sinon.stub (). Return ($ q.when ({})):
controlador:
y prueba
fuente
El fragmento de código:
Se puede escribir en una forma más concisa:
fuente