モックされた依存関係の実装を変更するごとにシングルテストベースをデフォルトのモックを拡張するの動作と- 次のテストを実行するときに元の実装に戻す。
もっと簡単に言うと、これは私が達成しようとしていることです。
現在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
});
});
いくつかの戦略を試しましたが、満足できると定義できる解決策は見つかりませんでした。
pros
cons
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'
});
pros
cons
コード:
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'
});
pros
cons
コード:
__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();
});
cons
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 the original mocked value?
});
テストを記述するための素敵なパターンは、現在のモジュールをテストするために必要なデータを返すセットアップファクトリ関数を作成することです。
以下は、2番目の例に続くサンプルコードですが、再利用可能な方法でデフォルト値とオーバーライド値を提供できます。
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
return {
mockedModule: jest.doMock('../myModule', () => mockedFunctions)
}
}
it("should return true for module a", () => {
const { mockedModule } = setup();
expect(mockedModule.a()).toEqual(true)
});
it("should return override for module a", () => {
const EXPECTED_VALUE = "override"
const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
});
});
mockFn.mockImplementation(fn) を使用します。
デフォルトの実装をbeforeEach
に配置します。モックは、すべてのテストの前にこれにリセットされます。
オーバーライドするには、テストでmockImplementation
を使用します。
これは、テスト内のすべてまたはすべての呼び出しに対するモックの動作をオーバーライドし、次のテストの前にbeforeEach
実装によって上書きされます。
例えば:
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// ...
});
パーティーに少し遅れましたが、他の誰かがこれに問題を抱えている場合。
反応ネイティブ開発には、TypeScript、ES6、およびbabelを使用します。
通常、外部NPMモジュールはルート__mocks__
ディレクトリでモックします。
特定のテスト用にaws-amplifyのAuthクラスのモジュールの特定の機能をオーバーライドしたかったのです。
import { Auth } from 'aws-amplify';
import GetJwtToken from './GetJwtToken';
...
it('When idToken should return "123"', async () => {
const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({
getIdToken: () => ({
getJwtToken: () => '123',
}),
}));
const result = await GetJwtToken();
expect(result).toBe('123');
spy.mockRestore();
});
要点: https://Gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2