我有一个经过 CRA 重新连接的 Typescript React 应用程序。
Jest全球进口。
为了使用笑话模拟,我必须编写
jest.mock('module-name')
上方 describe()
块并位于同一文件中,例如
import { act, render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
import { something } from 'my-module';
// 150 of my 300 test suites contain these.
// THERE IS NO IMPLEMENTATION and automock is fine
// BUT ONLY IF I opt-in.
// The other 150 test suites might have an implementation;
// Or they might use REAL modules and not mocks.
// This is why I don't want to just turn on `autoMock`.
// And I don't want to add this to `testSetup.js` because the OTHER 150
// do not need them.
// But I want to find a way to call something like `TestUtilities.mockStandard()` for the first 150 test suites.
jest.mock('my-module');
jest.mock('my-module2');
jest.mock('my-module3');
jest.mock('my-module4');
jest.mock('my-module5');
jest.mock('my-module6');
jest.mock('my-module7');
describe('MyComponent', () => {
afterAll(() => {
jest.unmock('my-module');
jest.unmock('my-module2');
jest.unmock('my-module3');
jest.unmock('my-module4');
jest.unmock('my-module5');
jest.unmock('my-module6');
jest.unmock('my-module7');
});
afterEach(() => {
jest.resetAllMocks();
jest.useRealTimers();
});
test('component renders', async () => {
(something as jest.MockedFunction<typeof something>).mockImplementation(() => 'banana');
const { container } = render(<MyComponent></MyComponent>);
expect(screen.queryByText('banana')).toBeVisible();
});
});
现在我有几百个测试套件和数千个测试。
其中一些有我想嘲笑的常见事物(例如
my-module
),但不是全部。
所以我不想使用
testSetup.js
来模拟所有测试中的模块,但我 DO WANT 找到一种不必一遍又一遍地编写 jest.mock()
的方法。
所以我尝试创建一个实用程序模块,如下所示:
const TestUtilities = {
mockMyModule: () => {
jest.mock('my-module');
},
unmockMyModule: () => {
jest.unmock('my-module');
},
};
export default TestUtilities;
然后修改原来的测试:
import { act, render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
import { something } from 'my-module';
import TestUtilities from './TestUtilities';
TestUtilities.mockMyModule();
describe('MyComponent', () => {
afterAll(() => {
TestUtilities.unmockMyModule();
});
afterEach(() => {
jest.resetAllMocks();
jest.useRealTimers();
});
test('component renders', async () => {
(something as jest.MockedFunction<typeof something>).mockImplementation(() => 'banana');
const { container } = render(<MyComponent></MyComponent>);
expect(screen.queryByText('banana')).toBeVisible();
});
});
不幸的是,现在测试的行为就好像
my-module
没有被嘲笑:(
有没有办法重新使用这些
jest.mock()
块?
似乎您有一半的测试用例可以使用默认的模拟实现,而另一半则需要特殊的实现。
如果是这种情况,您可能想尝试以下操作。
假设目录结构如下:
.
└── src/
└── modules/
├── dependency-n.js
├── __mocks__/
│ └── dependency-n.js
├── dependent.js
└── dependent.test.js
您可以使用测试中定义的全局变量来更改手动模拟的模拟实现的行为。
模拟/dependency-n.js
let mocked = jest.fn();
if (globals.useAltMockForDepN) {
mocked = jest.fn(() => {
// Your custom mocking implementation based on calling test
})
}
export default mocked;
dependent.test.js
import { something } from 'dependency-n';
jest.mock('dependency-n');
describe('MyDependentComponent', () => {
afterAll(() => {
jest.unmock('dependency-module-n');
});
afterEach(() => {
// Possibly use in afterAll instead
globals.useAltMockForDepN = false
});
test('component renders', async () => {
// Possibly use in beforeAll
globals.useAltMockForDepN = true;
// Now do your testing
});
});
这实际上只会让您在一半的测试中不需要自定义模拟实现,并且您仍然需要在所有测试中调用
jest.mock()
,除非您愿意/能够模拟每个导入的模块,然后您可以设置automock: true
。如果您确实想使用 automock: true
,那么您不需要在测试中调用 jest.mock()
,但是您将需要为您不想模拟的所有导入模块调用 jest.unmock()
。
我有一个我认为微不足道的要求。
您的场景不是全有或全无的情况,因此您必须编写代码来区分特殊情况,不幸的是,没有办法解决它。