使用Jest模拟Es6类

我试图用接收参数的构造函数来模拟一个ES6类,然后在类上模拟不同的类function,继续使用Jest进行testing。

问题是我找不到任何文件如何解决这个问题。 我已经看过这篇文章 ,但是这并不能解决我的问题,因为OP实际上甚至不需要模拟这个类。 在这篇文章中的另一个答案也没有详细说明,没有指出任何在线文档,不会导致可复制的知识,因为它只是一个代码块。

所以说我有以下课程:

//socket.js; module.exports = class Socket extends EventEmitter { constructor(id, password) { super(); this.id = id; this.password = password; this.state = constants.socket.INITIALIZING; } connect() { // Well this connects and so on... } }; //__tests__/socket.js jest.mock('./../socket'); const Socket = require('./../socket'); const socket = new Socket(1, 'password'); expect(Socket).toHaveBeenCalledTimes(1); socket.connect() expect(Socket.mock.calls[0][1]).toBe(1); expect(Socket.mock.calls[0][2]).toBe('password'); 

很明显,我试图嘲笑套接字和类函数连接的方式是错误的,但我找不到正确的方式来这样做。

请在你的回答中解释你为了嘲笑这件事而采取的逻辑步骤,以及为什么他们每个人都是必要的+如果可能,请提供外部链接给Jest官方文档!

谢谢您的帮助!

我不能真正帮助文档或全面的解释,因为到目前为止,官方文档中没有任何内容解释如何做到这一点。 但是我可以给你一些有用的代码,并分享一些意见。

什么工程(对我来说):

  1. 对于任何需要跟踪调用的类方法,通过调用jest.fn()来创build一个模拟函数。 在下一步使用这些。
  2. 调用MockedClass.mockImplementation() 。 传入一个箭头函数,该函数返回包含任何模拟方法的对象,每个方法都设置为自己的模拟函数(在步骤1中创build)。
  3. 不要使用手动模拟(__mocks__文件夹)来模拟ES6类。 由此产生的模拟是无用的,并防止上述工作。

一个例子胜过千言万语,所以这是代码。

首先,为你的代码

如果你要添加下面的设置代码,你的testing应该通过:

 const connectMock = jest.fn(); // Lets you check if `connect()` was called, if you want Socket.mockImplementation(() => { return { connect: connectMock }; }); 

(注意,在你的代码中: Socket.mock.calls[0][1]应该是[0][0][0][2]应该是[0][1]

接下来是一个人为的例子

内嵌一些解释。

mocked-class.js 。 注意,这个代码在testing过程中从不被调用。

 export default class MockedClass { constructor() { console.log('Constructed'); } mockedMethod() { console.log('Called mockedMethod'); } } 

嘲笑类消费者 。 这个类使用模拟类创build一个对象。 我们希望它创造一个嘲笑的版本,而不是真实的东西。

 import MockedClass from './mocked-class'; export default class MockedClassConsumer { constructor() { this.mockedClassInstance = new MockedClass('yo'); this.mockedClassInstance.mockedMethod('bro'); } } 

mocked-class-consumer.test.js – testing:

 import MockedClassConsumer from './mocked-class-consumer'; import MockedClass from './mocked-class'; jest.mock('./mocked-class'); // Mocks the function that creates the class; replaces it with a function that returns undefined. // console.log(MockedClass()); // logs 'undefined' let mockedClassConsumer; const mockedMethodImpl = jest.fn(); beforeAll(() => { MockedClass.mockImplementation(() => { // Replace the class-creation method with this mock version. return { mockedMethod: mockedMethodImpl // Populate the method with a reference to a mock created with jest.fn(). }; }); mockedClassConsumer = new MockedClassConsumer(); }); it('The MockedClassConsumer instance should have been created', () => { // console.log(MockedClass()); // logs a jest-created object with a mockedMethod: property, because the mockImplementation has been set now. expect(mockedClassConsumer).toBeTruthy(); }); it('We can check if the consumer called the class constructor', () => { expect(MockedClass).toHaveBeenCalled(); // Constructor has been called expect(MockedClass.mock.calls[0][0]).toEqual('yo'); // ... with the string 'yo' }); it('We can check if the consumer called a method on the class instance', () => { expect(mockedMethodImpl).toHaveBeenCalledWith('bro'); // Checking for method call using the stored reference to the mock function // It would be nice if there were a way to do this directly from MockedClass.mock }); 

什么不行(对我来说)

调用jest.mock('./mocked-class',()=> {…此处的工厂代码})

不pipe我用作工厂代码, new MockedClass()抛出TypeError: MockedClass.default is not a constructor

我认为这可能是一个错误。 这实际上应该和MockedClass.mockImplementation()一样,和手动模拟一样,但是显然不是。

手动嘲笑

由此产生的模拟是无用的,并防止上述工作。