javascript - Hvordan løser jeg et promise i en AngularJS enhedstest


Jeg bruger den grundlæggende karma/jasmine-opsætning til at teste min Angular-kode. Her er min 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() kalder mockSuperheroData.getSuperheroes(), som returnerer et løfte (promise). Hvordan tvinger jeg løftet til at returnere det, jeg ønsker, i en enhedstest? Hvor kan jeg tilknytte mig løftet for at mocke dets returværdi?

Svar #1

Hvordan tvinger jeg løftet til at returnere det, jeg vil, i en enhedstest?

Grundlæggende skal du kalde resolve på Deferred:

deferred.resolve(100);

Du kan enten sætte det direkte før return deferred.promise eller i en asynkron setTimeout.

Svar #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);
  });
});

Det skal nævnes, at fordi $q er integreret med $rootScope, skal du ikke kun løse det udskudte objekt, men du skal også udbrede ændringerne ved at kalde $rootScope.$apply.

Jeg skrev en blog om at latterliggøre Angular-løfter på projectpoppycock

og jeg skrev et fungerende eksempel, med tests, på plunkr

Jeg kan virkelig godt lide den måde, du injicerer mock-tjenesten som en afhængighed af controlleren ved at bruge $controller-tjenesten, jeg må måske revidere min måde at gøre dette på. Din måde er bedre :) Tak!