[解決済み] モックの実装を単体テストごとに変更する方法【Jestjs
2022-05-03 19:28:38
質問
私は、以下のことを望んでいます。 モック化された依存関係の実装を変更する を、その都度 単一テストベース によって デフォルトのモックを拡張する の動作と 元に戻す を、次のテスト実行時に元の実装に戻すことができます。
もっと簡単に言うと、私が実現しようとしているのはこういうことです。
- 模擬 依存関係
- モック実装の変更・拡張 一つのテストで
- 差し戻し 次のテストが実行されたときに元のモックに戻す
現在、私は
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(オブジェクト, メソッド名)
コンサ
-
元に戻すことができない
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?
});
解決方法は?
テストを書くための良いパターンは、現在のモジュールをテストするために必要なデータを返すセットアップファクトリ関数を作成することです。
以下は、2つ目の例に従ったサンプルコードですが、デフォルト値とオーバーライド値を再利用可能な方法で提供することができます。
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
beforeEach(() => {
jest.resetModules();
});
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
jest.doMock('../myModule', () => mockedFunctions)
return {
mockedModule: require('../myModule')
}
}
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)
});
});
重要なのは、あなたが
なければならない
を使用してキャッシュされたモジュールをリセットします。
jest.resetModules()
. これは
beforeEach
または同様のティアダウン機能
詳しくは、jestオブジェクトのドキュメントをご覧ください。 https://jestjs.io/docs/jest-object .
関連
-
Vueがechartsのtooltipにクリックイベントを追加するケーススタディ
-
vueのグローバルがscss(mixin)を導入。
-
[解決済み】JavaScript TypeError: null のプロパティ 'style' を読み取ることができない
-
[解決済み] Jestを使用して単一のテストを実行するにはどうすればよいですか?
-
[解決済み] Jestを使用して1つのファイルをテストするにはどうすればよいですか?
-
[解決済み] JavaScriptのオブジェクトが空であることをテストするにはどうすればよいですか?
-
[解決済み] JavaScriptで要素のクラスを変更するにはどうすればよいですか?
-
[解決済み] プライベートメソッド、フィールド、インナークラスを持つクラスをテストするにはどうすればよいですか?
-
[解決済み] Mockitoでvoidメソッドをモックする方法
-
[解決済み] Pythonの関数が例外を投げるかどうかをテストするにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JavaScriptのクロージャの説明
-
vueが定義するプライベートフィルタと基本的な使い方
-
vueにおけるfilterの適用シーンについて解説します。
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み】Node Version Manager のインストール - nvm コマンドが見つかりません。
-
[解決済み】"フォームが接続されていないため、フォームの送信がキャンセルされました "というエラーの取得について
-
[解決済み】Node.js Error: Cannot find module express
-
[解決済み] TypeError: $.ajax(...) is not a function?
-
[解決済み】ExpressJS : res.redirect()が期待通りに動かない?
-
OSSアップロードエラーを解決する: net::ERR_SSL_PROTOCOL_ERROR