web-dev-qa-db-fra.com

Comment se moquer d'un constructeur comme new Date ()

J'ai une méthode qui dépend de new Date Pour créer un objet date et ensuite le manipule. Je teste que la manipulation fonctionne comme prévu, j'ai donc besoin de comparer la date retournée avec la date attendue. Pour ce faire, je dois m'assurer que new Date Renvoie la même valeur dans le test et dans la méthode testée. Comment puis je faire ça?

Existe-t-il un moyen de se moquer réellement de la valeur de retour d'une fonction constructeur?

Je pourrais créer un module qui peut être requis avec une fonction qui fournit un objet de date et peut être moqué. Mais cela semble être une abstraction inutile dans mon code.

un exemple de fonction à tester ...

module.exports = {
  sameTimeTomorrow: function(){
    var dt = new Date();
        dt.setDate(dt + 1);
    return dt;
  }
};

comment puis-je me moquer de la valeur de retour de new Date()?

23
Seth Feldkamp

Vous pouvez utiliser spyOn de jasmine (la plaisanterie est construite sur jasmine) pour se moquer du prototype de Date pour getDate comme suit:

spyOn(Date.prototype, 'setDate').and.returnValue(DATE_TO_TEST_WITH);

SpyOn nettoiera également après son auto et ne dure que pour la portée du test.

12
linuxdan

Vous pouvez vous moquer d'un constructeur comme new Date () en utilisant jest.spyOn comme ci-dessous:

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

Et la sortie ressemble à:

Normal:    1566424897579
Mocked:    1466424490000
Restored:  1566424897608
8
Yuci

Vous pouvez remplacer le constructeur Date par une fonction simulée qui renvoie votre objet Date construit avec une valeur de date que vous avez spécifiée:

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

Vous pouvez tester l'exemple ici: https://repl.it/@miluoshi5/jest-mock-date

7
Miluoshi

Vous pouvez remplacer le constructeur Date par quelque chose qui renvoie toujours une date codée en dur, puis la remettre à la normale une fois terminé.

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);
1
Ben Taber

Je viens d'écrire un test de plaisanterie et j'ai pu stub new Date() avec global.Date = () => now

1
David

Vous pouvez utiliser date-faker pour simuler ce que retourne Date () ou Date.now ().

import { dateFaker } from 'date-faker'; // var { dateFaker } = require('date-faker');

// will return tomorrow, shift by one unit
dateFaker.add(1, 'day'); 

// shift by several units
dateFaker.add({ year: 1, month: -2, day: 3 });

// set up specific date, accepts Date or time string
dateFaker.set('2019/01/24'); 

dateFaker.reset();
0
MatGar