web-dev-qa-db-fra.com

Se moquer des dates dans les tests AngularJS/Jasmine

J'ai une directive qui initialise l'objet Date plusieurs fois dans plusieurs fonctions. Lorsque l’unité teste les fonctions individuelles, je peux gérer l’épinglage de la date comme ceci:

(function (global) {
  var NativeDate = global.Date;

  global.stubDateConstructor = function (fakeDate) {
      global.Date = function () {
          global.Date = NativeDate;
          return fakeDate;
      }
  }
}(this));

// ageInYears()
it("should return the age in years of the person given his/her birthdate", function() {
    stubDateConstructor(new Date('2010/01/01'));
    expect(ageInYears('01-01-1990')).toBe(20);
    stubDateConstructor(new Date('2010/01/01'));
    expect(ageInYears('01-01-1900')).toBe(110);
});

Pour uniter la directive elle-même, qui appelle ageInYears et plusieurs autres fonctions similaires, cela ne fonctionnera pas, car après un appel à Date (), stubDateConstructor aura réinitialisé Date () à l'objet Date réel.

Y a-t-il un moyen natif dans AngularJS/Jasmine de gérer ces situations, ou devrais-je regarder dans Sinon, par exemple?

32
Maarten

Jasmin (2.2) Clock peut se moquer des dates et des heures. 

http://jasmine.github.io/2.2/introduction.html#section- Mocking_the_Date

Par exemple (à partir de la documentation):

it("mocks the Date object and sets it to a given time", function() {
  var baseTime = new Date(2013, 9, 23);
  jasmine.clock().mockDate(baseTime);

  jasmine.clock().tick(50);
  expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
});
59
Rimian

Une solution simple consisterait à créer un service Angular Dates qui fournit pour vous des objets Date. Il pourrait même s'agir d'une seule méthode - Dates.now() - qui renvoie simplement la date actuelle en renvoyant new Date(). Vous utilisez ensuite ce service chaque fois que quelque chose nécessite l’affichage de la date du jour.

Cela vous permet ensuite d’injecter un autre service Dates lors du test unitaire, par exemple un service qui renvoie toujours une date spécifique de votre choix lorsqu’il est appelé, plutôt que l’heure actuelle.

12
Dave

angular.mock.TzDate serait une meilleure alternative native ici. cela vient comme une aide des moqueries angulaires et protège vraiment votre test du fuseau horaire du système ou de toute autre dépendance

https://docs.angularjs.org/api/ngMock/type/angular.mock.TzDate

cela joue bien avec Jasmine ou moka

1
prasanth shenoy

Je pouvais me moquer en utilisant une combinaison de faux timers de sinon pour simuler les minuteries de la fenêtre et de service d'intervalle simulé pour que angular reconnaisse les changements d'heure. Ici, countDownService testé utilise en interne javscript Date et angular's normal service d'intervalle quelque chose comme:

  describe('when start time was 3000 milliseconds and 1001 milliseconds have passed', function() {
    var startTime;
    var elapse;
    beforeEach(function(){
      this.clock = sinon.useFakeTimers();
      startTime = 3000;
      elapse = 1001;
    });

    var elapseMillis = function(intervalMock,sinonClock,millis){
      sinonClock.tick(millis);
      intervalMock.flush(millis);
    };

    it('elapsedMillis + timeRemainingMillis should == startime', 
      inject(function($rootScope,$interval,countdownService) {
        countdownService.startTimer(startTime);
        elapseMillis($interval,this.clock,elapse);
        //jasmine clock does not mock Date
        //see https://github.com/pivotal/jasmine/issues/361
        var elapsedMillis = countdownService.getElapsedMillis();
        var timeRemainingMillis = countdownService.getTimeRemainingMillis();
        expect(elapsedMillis + timeRemainingMillis).toEqual(startTime);
        expect(elapsedMillis).toEqual(elapse);
    }));

    afterEach(function(){
      this.clock.restore();
        startTime = 0;
        elapse = 0;
    });
  });

Vous voudrez également vous assurer d'inclure le sinon-timers-1.8.1.js sinon de js dans votre propriété de fichiers karma.conf.js.

0
ossek