使用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官方文档!
谢谢您的帮助!
我不能真正帮助文档或全面的解释,因为到目前为止,官方文档中没有任何内容解释如何做到这一点。 但是我可以给你一些有用的代码,并分享一些意见。
什么工程(对我来说):
- 对于任何需要跟踪调用的类方法,通过调用
jest.fn()
来创build一个模拟函数。 在下一步使用这些。 - 调用
MockedClass.mockImplementation()
。 传入一个箭头函数,该函数返回包含任何模拟方法的对象,每个方法都设置为自己的模拟函数(在步骤1中创build)。 - 不要使用手动模拟(__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()一样,和手动模拟一样,但是显然不是。
手动嘲笑
由此产生的模拟是无用的,并防止上述工作。