Как высмеять конструктор, как новый Date()
У меня есть метод, который зависит от new Date
, чтобы создать объект даты, а затем манипулировать им. Я тестирую, что манипуляции работают так, как ожидалось, поэтому мне нужно сравнить возвращаемую дату с ожидаемой датой. Для этого мне нужно убедиться, что new Date
возвращает то же значение в тесте и в тестируемом методе. Как я могу это сделать?
Есть ли способ на самом деле высмеять возвращаемое значение функции-конструктора?
Я мог бы создать модуль, который может потребоваться с помощью функции, которая предоставляет объект даты и может быть издевательством. Но это похоже на ненужную абстракцию в моем коде.
пример функции, подлежащей тестированию...
module.exports = {
sameTimeTomorrow: function(){
var dt = new Date();
dt.setDate(dt + 1);
return dt;
}
};
как мне высмеять возвращаемое значение new Date()
?
Ответы
Ответ 1
Вы можете использовать jasmine spyOn (шутка построена на жасмине), чтобы продумать прототип даты для getDate следующим образом:
spyOn(Date.prototype, 'setDate').and.returnValue(DATE_TO_TEST_WITH);
SpyOn также будет очищаться после него сам и будет продолжаться только в рамках теста.
Ответ 2
Вы можете переопределить конструктор Date с помощью фиктивной функции, которая возвращает созданный вами объект Date с указанным вами значением даты:
var yourModule = require('./yourModule')
test('Mock Date', () => {
const mockedDate = new Date(2017, 11, 10)
const originalDate = Date
global.Date = jest.fn(() => mockedDate)
global.Date.setDate = originalDate.setDate
expect(yourModule.sameTimeTomorrow().getDate()).toEqual(11)
})
Вы можете проверить пример здесь: https://repl.it/@miluoshi5/jest-mock-date
Ответ 3
Вы можете заменить конструктор Date тем, что всегда возвращает жестко запрограммированную дату, и после этого верните его в нормальное состояние.
var _Date = null;
function replaceDate() {
if (_Date) {
return
};
_Date = Date;
Object.getOwnPropertyNames(Date).forEach(function(name) {
_Date[name] = Date[name]
});
// set Date ctor to always return same date
Date = function() { return new _Date('2000-01-01T00:00:00.000Z') }
Object.getOwnPropertyNames(_Date).forEach(function(name) {
Date[name] = _Date[name]
});
}
function repairDate() {
if (_Date === null) {
return;
}
Date = _Date;
Object.getOwnPropertyNames(_Date).forEach(function(name) {
Date[name] = _Date[name]
});
_Date = null;
}
// test that two dates created at different times return the same timestamp
var t0 = new Date();
// create another one 100ms later
setTimeout(function() {
var t1 = new Date();
console.log(t0.getTime(), t1.getTime(), t0.getTime() === t1.getTime());
// put things back to normal when done
repairDate();
}, 100);
Ответ 4
Я только что написал тест на шутку и смог заглушить new Date()
с global.Date = () => now
Ответ 5
Вы можете смоделировать конструктор, например, new Date(), используя jest.spyOn
, как показано ниже:
test('mocks a constructor like new Date()', () => {
console.log('Normal: ', new Date().getTime())
const mockDate = new Date(1466424490000)
const spy = jest
.spyOn(global, 'Date')
.mockImplementation(() => mockDate)
console.log('Mocked: ', new Date().getTime())
spy.mockRestore()
console.log('Restored: ', new Date().getTime())
})
И результат выглядит так:
Normal: 1566424897579
Mocked: 1466424490000
Restored: 1566424897608
Ответ 6
Вот что я делаю сейчас, и это работает и не загромождает мою подпись метода.
newDate.js
module.exports = function(){
return new Date();
};
someModule.js
var newDate = require('newDate.js');
module.exports = {
sameTimeTomorrow: function(){
var dt = newDate();
dt.setDate(dt.getDate() + 1);
return dt;
}
};
someModule-test.js
jest.dontMock('someModule.js');
describe('someModule', function(){
it('sameTimeTomorrow', function(){
var newDate = require('../../_app/util/newDate.js');
newDate.mockReturnValue(new Date(2015, 02, 13, 09, 15, 40, 123));
var someModule = require('someModule.js');
expect(someModule.sameTimeTomorrow().toString()).toBe(new Date(2015, 02, 14, 09, 15, 40, 123).toString());
});
});