37

我有一个指令在几个函数中多次初始化 Date 对象。当对单个函数进行单元测试时,我可以像这样处理存根日期:

(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);
});

对于调用ageInYears 和其他几个类似函数的指令本身的单元测试,这将不起作用,因为我在一次调用Date() stubDateConstructor 后会将Date() 重置为真实的Date 对象。

AngularJS / Jasmine 中是否有本地方式来处理这些情况,或者我应该研究一下Sinon,例如?

4

4 回答 4

66

Jasmine (2.2) 时钟可以模拟日期和时间。

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

例如(来自文档):

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);
});
于 2014-09-28T01:32:07.443 回答
12

一个直接的解决方案是创建一个为您Dates提供Date对象的 Angular 服务——它甚至可能只有一个方法——Dates.now()它只是通过返回来发回当前日期new Date()。然后,每当需要获取当前日期时,您就可以使用此服务。

然后,这允许您Dates在单元测试时注入不同的服务,例如,在调用时总是返回您选择的特定日期,而不是当前时间。

于 2013-10-23T08:20:19.797 回答
1

angular.mock.TzDate 在这里会是一个更好的原生替代品。这是 Angular 模拟的助手,真正保护您的测试免受系统时区或任何其他依赖项的影响

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

这很适合茉莉花或摩卡咖啡

于 2017-09-01T23:16:32.297 回答
0

我能够使用sinon 的假计时器的组合来模拟窗口的计时器和 angular 的模拟间隔服务,以便 angular 识别时间变化。在这里,被测countDownService在内部使用了javscriptDate和angular的正常间隔服务,比如:

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

您还需要确保并将 sinon js 包含sinon-timers-1.8.1.js在您的 karma.conf.js 文件属性中。

于 2014-02-04T16:12:05.947 回答