更新:
所有这些信息和更多信息现已添加到新指南“ES6 Class Mocks”中的 Jest 文档中。
完全披露:我写的。 :-)
模拟 ES6 类的关键是知道ES6 类是一个函数。因此,mock 也必须是一个函数。
- 调用
jest.mock('./mocked-class.js');,同时导入'./mocked-class.js'。
- 对于要跟踪调用的任何类方法,创建一个指向模拟函数的变量,如下所示:
const mockedMethod = jest.fn();。在下一步中使用它们。
- 致电
MockedClass.mockImplementation()。传入一个箭头函数,该函数返回一个包含任何模拟方法的对象,每个方法都设置为自己的模拟函数(在第 2 步中创建)。
- 可以使用手动模拟(__mocks__ 文件夹)模拟 ES6 类来完成相同的操作。在这种情况下,导出的模拟是通过调用
jest.fn().mockImplementation() 创建的,具有与上面(3)中描述的相同的参数。这将创建一个模拟函数。在这种情况下,您还需要导出任何要监视的模拟方法。
- 同样的事情可以通过调用
jest.mock('mocked-class.js', factoryFunction) 来完成,其中 factoryFunction 与上面 3 和 4 中传递的参数相同。
一个例子值一千字,所以这里是代码。
此外,这里有一个 repo 演示了所有这些:
https://github.com/jonathan-stone/jest-es6-classes-demo/tree/mocks-working
首先,对于您的代码
如果您要添加以下设置代码,您的测试应该会通过:
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。请注意,此代码在测试期间永远不会被调用。
export default class MockedClass {
constructor() {
console.log('Constructed');
}
mockedMethod() {
console.log('Called mockedMethod');
}
}
mocked-class-consumer.js。此类使用模拟类创建一个对象。我们希望它创建一个模拟版本而不是真实版本。
import MockedClass from './mocked-class';
export default class MockedClassConsumer {
constructor() {
this.mockedClassInstance = new MockedClass('yo');
this.mockedClassInstance.mockedMethod('bro');
}
}
mocked-class-consumer.test.js - 测试:
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().
};
});
});
beforeEach(() => {
MockedClass.mockClear();
mockedMethodImpl.mockClear();
});
it('The MockedClassConsumer instance can be created', () => {
const mockedClassConsumer = new MockedClassConsumer();
// 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).not.toHaveBeenCalled(); // Ensure our mockClear() is clearing out previous calls to the constructor
const mockedClassConsumer = new MockedClassConsumer();
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', () => {
const mockedClassConsumer = new MockedClassConsumer();
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
});