Eu tenho myService
esse usos myOtherService
, que faz uma chamada remota, retornando a promessa:
angular.module('app.myService', ['app.myOtherService'])
.factory('myService', [
myOtherService,
function(myOtherService) {
function makeRemoteCall() {
return myOtherService.makeRemoteCallReturningPromise();
}
return {
makeRemoteCall: makeRemoteCall
};
}
])
Para fazer um teste de unidade, myService
preciso zombar myOtherService
, de modo que seu makeRemoteCallReturningPromise
método retorne uma promessa. É assim que eu faço:
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 você pode ver acima, a definição do meu mock depende $q
, da qual eu tenho que carregar usando inject()
. Além disso, a injeção do mock deve estar acontecendo module()
, o que deve acontecer antes inject()
. No entanto, o valor da simulação não é atualizado após a alteração.
Qual é a maneira correta de fazer isso?
javascript
angularjs
unit-testing
mocking
jasmine
Georgii Oleinikov
fonte
fonte
myService.makeRemoteCall()
? Nesse caso, o problema émyService
não ter omakeRemoteCall
, nem nada a ver com o seu escárniomyOtherService
.Respostas:
Não sei por que o modo como você fez isso não funciona, mas geralmente faço com a
spyOn
função Algo assim:Lembre-se também de que você precisará fazer uma
$digest
chamada para que athen
função seja chamada. Consulte a seção Teste da documentação $ q .------EDITAR------
Depois de olhar mais de perto o que você está fazendo, acho que vejo o problema no seu código. No
beforeEach
, você está definindomyOtherServiceMock
um objeto totalmente novo. O$provide
nunca verá esta referência. Você só precisa atualizar a referência existente:fonte
andCallFake
você pode usarandReturnValue(deferred.promise)
(ouand.returnValue(deferred.promise)
no Jasmine 2.0+). Você precisa definirdeferred
antes de ligarspyOn
, é claro.$digest
nesse caso quando não tem acesso ao escopo?$rootScope
e invoca$digest
isso.$q.when()
codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrongTambém podemos escrever a implementação do jasmim de retornar a promessa diretamente por espião.
Para Jasmine 2:
(copiado dos comentários, graças ao ccnokes)
fonte
spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue($q.when({}));
acabei de matar meia hora descobrindo isso.fonte
Você pode usar uma biblioteca de stubbing como sinon para zombar de seu serviço. Você pode retornar $ q.when () como sua promessa. Se o valor do objeto do escopo vier do resultado da promessa, você precisará chamar scope. $ Root. $ Digest ().
fonte
$rootScope.$digest()
para obter a promessa de ser resolvidousando
sinon
:Sabido que,
httpPromise
pode ser:fonte
Honestamente ... você está fazendo isso da maneira errada, confiando no injetar para simular um serviço em vez do módulo. Além disso, chamar injetar em um beforeEach é um anti-padrão, pois dificulta a zombaria por teste.
Aqui está como eu faria isso ...
Agora, quando você injeta seu serviço, ele terá um método de zombaria adequado para uso.
fonte
Achei que a função útil e facada de serviço como sinon.stub (). Returns ($ q.when ({})):
controlador:
e teste
fonte
O trecho de código:
Pode ser escrito de uma forma mais concisa:
fonte