これは不可能だと思い始めていますが、とにかくお願いしたいと思います。
私のES6モジュールの1つが特定の方法で別のES6モジュールを呼び出すことをテストしたいです。 Jasmineを使えば、これはとても簡単です -
アプリコード:
// myModule.js
import dependency from './dependency';
export default (x) => {
dependency.doSomething(x * 2);
}
そしてテストコード:
//myModule-test.js
import myModule from '../myModule';
import dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
spyOn(dependency, 'doSomething');
myModule(2);
expect(dependency.doSomething).toHaveBeenCalledWith(4);
});
});
Jestと同等のものは何ですか?私はこれがやりたいことのような単純なことのように感じます、しかし私はそれを理解しようとして私の髪を引き裂いています。
一番近いのは、import
をrequire
に置き換え、それらをテスト/関数の中に移動することです。どちらも私がやりたいことではありません。
// myModule.js
export default (x) => {
const dependency = require('./dependency'); // yuck
dependency.doSomething(x * 2);
}
//myModule-test.js
describe('myModule', () => {
it('calls the dependency with double the input', () => {
jest.mock('../dependency');
myModule(2);
const dependency = require('../dependency'); // also yuck
expect(dependency.doSomething).toBeCalledWith(4);
});
});
嬉しいことに、dependency.js
の中の関数がデフォルトのエクスポートであるとき、私は全部がうまくいくようにしたいです。しかし、デフォルトのエクスポートをスパイしてもJasmineではうまくいかないことがわかっています(少なくともうまくいくことはあり得ませんでした)ので、Jestでもそれが可能であることを望みません。
私はimport *
を含むハックを使うことによってこれを解決することができました。名前付きとデフォルトの両方のエクスポートでも機能します。
名前付きエクスポートの場合:
// dependency.js
export const doSomething = (y) => console.log(y)
// myModule.js
import { doSomething } from './dependency';
export default (x) => {
doSomething(x * 2);
}
// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
dependency.doSomething = jest.fn(); // Mutate the named export
myModule(2);
expect(dependency.doSomething).toBeCalledWith(4);
});
});
またはデフォルトのエクスポートの場合:
// dependency.js
export default (y) => console.log(y)
// myModule.js
import dependency from './dependency'; // Note lack of curlies
export default (x) => {
dependency(x * 2);
}
// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
dependency.default = jest.fn(); // Mutate the default export
myModule(2);
expect(dependency.default).toBeCalledWith(4); // Assert against the default
});
});
Mihai Damianが以下で非常に正しく指摘しているように、これはdependency
のモジュールオブジェクトを変更しているので、他のテストに「リーク」します。したがって、この方法を使用する場合は、元の値を保存してから、テストごとに元に戻す必要があります。これをJestで簡単に行うには、jest.fn()
の代わりに spyOn() methodを使用します。元の値を簡単に復元できるので、前述の「リーク」を避けることができます。
あなたはモジュールをモックし、スパイを自分で設定しなければなりません:
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency', () => ({
doSomething: jest.fn()
}))
describe('myModule', () => {
it('calls the dependency with double the input', () => {
myModule(2);
expect(dependency.doSomething).toBeCalledWith(4);
});
});
Andreasの回答にさらに追加する私はES6コードで同じ問題を抱えていましたが、インポートを変更したくありませんでした。それはハッキーだった。だから私はこれをしました
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');
describe('myModule', () => {
it('calls the dependency with double the input', () => {
myModule(2);
});
});
そして、 "__ mocks __"フォルダにdependency.jsと並行してdependency.jsを追加しました。これは私のために働きました。また、これにより、モック実装から適切なデータを返すことができました。モックするモジュールへの正しいパスを指定してください。
Jestを使用してES6依存関係モジュールのデフォルトのエクスポートをモックするには:
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');
// If necessary, you can place a mock implementation like this:
dependency.mockImplementation(() => 42);
describe('myModule', () => {
it('calls the dependency once with double the input', () => {
myModule(2);
expect(dependency).toHaveBeenCalledTimes(1);
expect(dependency).toHaveBeenCalledWith(4);
});
});
他の選択肢は私の場合にはうまくいきませんでした。
質問はすでに回答されていますが、次のように解決できます。
dependency.js
module.exports.doSomething = (x) => x
myModule.js:
const { doSomething } = require('./dependency')
module.exports = (x) => doSomething(x * 2)
myModule.spec.js:
jest.mock('../dependency')
const { doSomething } = require('../dependency')
const myModule = require('../myModule')
describe('myModule', () => {
it('calls the dependency with double the input', () => {
doSomething.mockImplementation((x) => x * 10)
myModule(2);
expect(doSomething).toHaveBeenCalledWith(4);
console.log(myModule(2)) // 40
});
});
私はこれを別の方法で解決しました。あなたのdependency.jsがあるとしましょう
export const myFunction = () => { }
以下の内容でdepdency.mock.jsファイルを作成します。
export const mockFunction = jest.fn();
jest.mock('dependency.js', () => ({ myFunction: mockFunction }));
テストでは、使用する依存関係を持つファイルをインポートする前に、
import { mockFunction } from 'dependency.mock'
import functionThatCallsDep from './tested-code'
it('my test', () => {
mockFunction.returnValue(false);
functionThatCallsDep();
expect(mockFunction).toHaveBeenCalled();
})