Javascript 如何模拟像 new Date() 这样的构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28504545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:53:34  来源:igfitidea点击:

How to mock a constructor like new Date()

javascriptjestjs

提问by Seth Feldkamp

I have a method which depends on new Dateto create a date object and then manipulates it. I'm testing that the manipulation works as expected, so I need to compare the returned date with expected date. In order to do that I need to make sure that new Datereturns the same value in the test and in the method being tested. How can I do that?

我有一个方法,它依赖于new Date创建一个日期对象然后操作它。我正在测试操作是否按预期工作,因此我需要将返回日期与预期日期进行比较。为了做到这一点,我需要确保new Date在测试和正在测试的方法中返回相同的值。我怎样才能做到这一点?

Is there a way to actually mock the return value of a constructor function?

有没有办法实际模拟构造函数的返回值?

I could create a module that can be required with a function that provides a date object and can be mocked. But that seems like an unnecessary abstraction in my code.

我可以创建一个模块,该模块可能需要一个提供日期对象并且可以被模拟的函数。但这在我的代码中似乎是不必要的抽象。

an example function to be tested...

要测试的示例函数...

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

how do I mock the return value of new Date()?

我如何模拟 的返回值new Date()

回答by linuxdan

You can use jasmine's spyOn (jest is built on jasmine) to mock Date's prototype for getDate as follows:

您可以使用 jasmine 的 spyOn(jest 建立在 jasmine 之上)来模拟 Date 的 getDate 原型,如下所示:

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

SpyOn will also clean up after it's self and only lasts for the scope of the test.

SpyOn 也会在它自己之后进行清理,并且只在测试范围内持续。

回答by Yuci

You can mock a constructor like new Date() using jest.spyOnas below:

您可以使用jest.spyOn如下方法模拟像 new Date() 这样的构造函数:

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

And the output looks like:

输出如下所示:

Normal:    1566424897579
Mocked:    1466424490000
Restored:  1566424897608

See the reference project on GitHub.

请参阅GitHub 上的参考项目

Note: If you are using TypeScript and you would encounter a compilation error, Argument of type '() => Date' is not assignable to parameter of type '() => string'. Type 'Date' is not assignable to type 'string'. In this case, a workaround is to use the mockdatelibrary, which can be used to change when "now" is. See this questionfor more details.

注意:如果您使用的是 TypeScript 并且会遇到编译错误,Argument of type '() => Date' is not assignable to parameter of type '() => string'. Type 'Date' is not assignable to type 'string'. 在这种情况下,解决方法是使用mockdate库,该库可用于更改“现在”的时间。有关更多详细信息,请参阅此问题

回答by Miluoshi

You can override Date constructor with an mocked function which returns your a constructed Date object with a date value you specified:

您可以使用模拟函数覆盖 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)
})

You can test the example here: https://repl.it/@miluoshi5/jest-mock-date

您可以在此处测试示例:https: //repl.it/@miluoshi5/jest-mock-date

回答by David

I just wrote a jest test and was able to stub new Date()with global.Date = () => now

我只是写了一个玩笑测试,并能够存根new Date()global.Date = () => now

回答by Ben Taber

You can replace the Date constructor with something that always returns a hardcoded date, and then put it back to normal when done.

您可以使用始终返回硬编码日期的内容替换 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);

回答by MatGar

You can use date-fakerto mock what new Date() or Date.now() returns.

您可以使用date-faker来模拟 new Date() 或 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();

回答by Seth Feldkamp

Here's what I'm doing now and this is working and doesn't clutter my method's signature.

这就是我现在正在做的事情,这是有效的并且不会弄乱我的方法签名。

newDate.js

新日期.js

module.exports = function(){
  return new Date();
};

someModule.js

someModule.js

var newDate = require('newDate.js');
module.exports = {
  sameTimeTomorrow: function(){
    var dt = newDate();
        dt.setDate(dt.getDate() + 1);
    return dt;
  }
};

someModule-test.js

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

});