デフォルトのモックの動作を拡張し、次のテストの実行時に元の実装に戻すことで、単一のテストごとにモックされた依存関係の実装を変更したいと思います。
もっと簡単に言えば、これは私が達成しようとしていることです:
- モック依存関係
- 単一のテストでモック実装を変更/拡張する
- 次のテストが実行されると、元のモックに戻ります
現在使用していJest v21
ます。
典型的なJestテストは次のようになります。
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
__tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
これが私がこれまでに試したことです:
1- mockFn.mockImplementationOnce(fn)
長所
- 最初の呼び出し後、元の実装に戻ります
短所
- テストが
b
複数回呼び出されると壊れます b
呼び出されない限り、元の実装に戻りません(次のテストでリークします)
コード:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
2- jest.doMock(moduleName、factory、options)
長所
- すべてのテストで明示的にリモックします
短所
- すべてのテストにデフォルトのモック実装を定義することはできません
- デフォルトの実装を拡張して、モックされた各メソッドを再宣言することを強制することはできません
コード:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
jest.doMock('../myModule', () => {
return {
a: jest.fn(() => true,
b: jest.fn(() => 'overridden',
}
});
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
3-セッターメソッドを使用した手動モック(ここで説明)
長所
- 模擬結果の完全な制御
短所
- ボイラープレートコードがたくさん
- 長期的に維持するのは難しい
コード:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
let a = true;
let b = true;
myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);
myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
a = true;
b = true;
};
export default myMockedModule;
__tests__/myTest.js
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myModule.__setB('overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
myModule.__reset();
});
4- jest.spyOn(object、methodName)
短所
mockImplementation
元のモックされた戻り値に戻れないため、次のテストに影響します
コード:
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
// Mock myModule
jest.mock('../myModule');
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// How to get back to original mocked value?
});