Ricerca nel sito web

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!