web-dev-qa-db-ja.com

モジュールのモックが解除されたときにJestでインポートされた名前付き関数をモックする方法

Jestでテストしようとしている次のモジュールがあります。

// myModule.js

export function otherFn() {
  console.log('do something');
}

export function testFn() {
  otherFn();

  // do other things
}

上記に示すように、いくつかの名前付き関数をエクスポートし、重要なことにtestFnotherFnを使用します。

Jestでは、testFnの単体テストを作成するときに、otherFnのエラーをotherFnの単体テストに影響させたくないため、testFn関数をモックしたいと思います。 ] _。私の問題は、それを行う最善の方法がわからないということです。

// myModule.test.js
jest.unmock('myModule');

import { testFn, otherFn } from 'myModule';

describe('test category', () => {
  it('tests something about testFn', () => {
    // I want to mock "otherFn" here but can't reassign
    // a.k.a. can't do otherFn = jest.fn()
  });
});

どんな助け/洞察も大歓迎です。

52
Jon Rubins

jest.requireActual()内でjest.mock()を使用する

jest.requireActual(moduleName)

モックの代わりに実際のモジュールを返します。モジュールがモック実装を受信するかどうかのすべてのチェックをバイパスします。

返されたオブジェクトを必要とし、そのオブジェクト内で拡散する場合、この簡潔な使用を好む:

// myModule.test.js

jest.mock('./myModule.js', () => (
  {
    ...(jest.requireActual('./myModule.js')),
    otherFn: () => {}
  }
))

describe(...)

このメソッドは、JestのManual Mocksドキュメントでも参照されています( Examples の終わり近く):

手動モックとその実際の実装の同期を維持するために、手動モックでjest.requireActual(moduleName)を使用し、エクスポートする前にモック関数で修正する実際のモジュールを要求することが役立つ場合があります。

32
gfullam
import m from '../myModule';

私にはうまくいきません、私は使用しました:

import * as m from '../myModule';

m.otherFn = jest.fn();
26
bobu

トランスコンパイルされたコードは、otherFn()が参照しているバインディングをbabelが取得することを許可しません。関数式を使用する場合、モックotherFn()を達成できるはずです。

// myModule.js
exports.otherFn = () => {
  console.log('do something');
}

exports.testFn = () => {
  exports.otherFn();

  // do other things
}

// myModule.test.js
import m from '../myModule';

m.otherFn = jest.fn();

しかし、前のコメントで@kentcdoddsが言及したように、おそらくotherFn()をモックしたくないでしょう。むしろ、otherFn()の新しい仕様を記述し、それが行っている必要な呼び出しをモックするだけです。

たとえば、otherFn()がhttpリクエストを行っている場合...

// myModule.js
exports.otherFn = () => {
  http.get('http://some-api.com', (res) => {
    // handle stuff
  });
};

ここでは、http.getをモックし、モックされた実装に基づいてアサーションを更新します。

// myModule.test.js
jest.mock('http', () => ({
  get: jest.fn(() => {
    console.log('test');
  }),
}));
10
vutran

私はこのパーティーに遅れているように見えますが、はい、これは可能です。

testFnは、otherFnを呼び出すだけで済みますモジュールを使用して

testFnがモジュールを使用してotherFnを呼び出す場合、otherFnのモジュールエクスポートはモックでき、testFnはモックを呼び出します。


これが実際の例です:

myModule.js

import * as myModule from './myModule';  // import myModule into itself

export function otherFn() {
  return 'original value';
}

export function testFn() {
  const result = myModule.otherFn();  // call otherFn using the module

  // do other things

  return result;
}

myModule.test.js

import * as myModule from './myModule';

describe('test category', () => {
  it('tests something about testFn', () => {
    const mock = jest.spyOn(myModule, 'otherFn');  // spy on otherFn
    mock.mockReturnValue('mocked value');  // mock the return value

    expect(myModule.testFn()).toBe('mocked value');  // SUCCESS

    mock.mockRestore();  // restore otherFn
  });
});
10

ここでの最初の答えに加えて、 babel-plugin-rewire を使用して、インポートされた名前付き関数もモックできます。 named function rewiring のセクションを表面的に確認できます。

ここでの状況に対する直接的な利点の1つは、関数から他の関数​​を呼び出す方法を変更する必要がないことです。

0