Издевательские даты в тестах AngularJS/Jasmine
У меня есть директива, которая несколько раз инициализирует объект 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);
});
Для unittesting самой директивы, которая вызывает ageInYears и несколько других подобных функций, это не будет работать, поскольку я после одного вызова Date() stubDateConstructor будет иметь reset Date() для реального объекта Date.
Есть ли собственный способ в AngularJS/Jasmine для обработки этих ситуаций, или я должен смотреть в Sinon, например.
Ответы
Ответ 1
Жасмин (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);
});
Ответ 2
Простое решение заключалось бы в создании службы Angular Dates
, которая предоставляет объекты Date
для вас - у нее может быть даже просто один метод - Dates.now()
-, который просто отправляет обратно текущую дату, возвращая new Date()
. Затем вы используете эту услугу, когда что-то должно получить текущую дату.
Затем это позволяет вам вводить другую службу Dates
при модульном тестировании, например, такую, которая всегда возвращает определенную дату по вашему выбору при вызове, а не текущее время.
Ответ 3
angular.mock.TzDate будет лучшей альтернативой. это приходит как помощник из angular mocks и по-настоящему безопасно защищает ваш тест из системного часового пояса или любых других зависимостей
https://docs.angularjs.org/api/ngMock/type/angular.mock.TzDate
это хорошо работает с Жасмином или моккой
Ответ 4
Я смог издеваться, используя комбинацию тайных поддельных таймеров, чтобы высмеять таймеры окна и angular сервисный интервал для angular для распознавания изменений времени. Здесь проверка countDownService использует внутренне как службу javscript Date
, так и angular normal Что-то вроде:
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;
});
});
Вы также захотите убедиться, что в свой файл karma.conf.js также включен sinon js sinon-timers-1.8.1.js
.