こんにちは、CX事業本部 IoT事業部の若槻です。
JavaScriptのテスティングフレームワークJestでは、テスト対象のModuleやFunctionのモックを作成するためのJest Objectがいくつか用意されています。
今回は、そのJest Objectのうちのjest.spyOn()の基本的な使い方を確認してみました。
確認してみた
確認を実施した環境は次の通りです。
npm ls jest typescript --depth=0
hoge-project@0.1.0
├── jest@26.6.3
└── typescript@3.9.10
jest.spyOn(object, methodName)
jest.spyOn(object, methodName)
を使用すると、Methodを含んだObjectのmock functionを作成する(=モックする)ことが出来ます。
下記はplay
Methodを持つvideo
をモックしているテスト例です。
video.ts
export const video = {
play() {
return true;
},
};
test/video.test.ts
import { video } from '../video';
test('plays video true', () => {
const spy = jest.spyOn(video, 'play');
const isPlaying = video.play();
expect(spy).toHaveBeenCalled();
expect(isPlaying).toBe(true);
spy.mockRestore();
});
テストを実行すると成功しました。
$ npx jest test/video.test.ts
PASS test/video.test.ts
✓ plays video true (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.011 s
Ran all test suites matching /test\/video.test.ts/i.
またjest.spyOn(object, methodName).mockImplementation(() => customImplementation)
のように使用すればMethodを上書きして戻り値を任意の値に指定することもできます。
test/video.test.ts
test('plays video false', () => {
const spy = jest.spyOn(video, 'play').mockImplementation(() => false);
const isPlaying = video.play();
expect(spy).toHaveBeenCalled();
expect(isPlaying).toBe(false);
spy.mockRestore();
});
テストを実行すると成功しました。
$ npx jest test/video.test.ts
PASS test/video.test.ts (5.252 s)
✓ plays video true (2 ms)
✓ plays video false (1 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 5.296 s
Ran all test suites matching /test\/video.test.ts/i.
Methodの上書きは、認証や外部への接続が必要となるMethodのテストで役に立ちそうですね。
jest.fn()との比較
前述したjest.spyOn
でのMethodの戻り値の上書きは、jest.fn()を使用した場合にも行えます。
比較のために同じvideo
をjest.fn()
でモックしてみます。mockReturnValue()
を使用します。
test/video.test.ts
test('plays videos false jest.fn()', () => {
(video.play as jest.Mock) = jest.fn().mockReturnValue(false);
const isPlaying = video.play();
expect(video.play).toHaveBeenCalled();
expect(isPlaying).toBe(false);
});
テストを実行すると成功しました。
$ npx jest test/video.test.ts
PASS test/video.test.ts (5.449 s)
✓ plays video true (2 ms)
✓ plays video false (1 ms)
✓ plays videos false jest.fn()
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.508 s, estimated 6 s
Ran all test suites matching /test\/video.test.ts/i.
jest.spyOn(object, methodName, accessType?)
Methodはgetterまたはsetterのいずれかを指定することができますが、spyOnの第三引数accessType
でget
またはset
を指定すれば、getterとsetterのそれぞれをモックしてテストすることができます。
下記はplay
Methodを持つvideo
をモックしているテスト例です。
video_and_audio.ts
export const video = {
// it's a getter!
get play() {
return true;
},
};
export const audio = {
_volume: 0,
// it's a setter!
set volume(value) {
this._volume = value;
},
get volume() {
return this._volume;
},
};
test/video_and_audio.test.ts
import { video, audio } from '../video_and_audio';
test('plays video', () => {
const spy = jest.spyOn(video, 'play', 'get'); // we pass 'get'
const isPlaying = video.play;
expect(spy).toHaveBeenCalled();
expect(isPlaying).toBe(true);
spy.mockRestore();
});
test('plays audio', () => {
const spy = jest.spyOn(audio, 'volume', 'set'); // we pass 'set'
audio.volume = 100;
expect(spy).toHaveBeenCalled();
expect(audio.volume).toBe(100);
spy.mockRestore();
});
テストを実行すると成功しました。
npx jest test/video_and_audio.test.ts
PASS test/video_and_audio.test.ts (5.647 s)
✓ plays video (3 ms)
✓ plays audio
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 5.705 s
Ran all test suites matching /test\/video_and_audio.test.ts/i.
setterやgetterをテストしたい場合はjest.spyOn()
が役に立ちそうですね。
おわりに
jest.spyOn()
の基本的な使い方を確認してみました。
今までテスト時のモックはjest.fn()
を使うことがほとんどでjest.spyOn()
には明るくなかったので、今回確認できて良かったです。
以上