React×Jestの基礎知識
前述:Jestとは
・実行対象ファイル
ファイル名が.test.tsまたは.spec.tsで終わるもの
・jest実行コマンド
全てのテストを実行→ yarn test
差分のあるファイルのみ実行→ yarn test -o
基礎概念
describe
JestにおいてTest Suite(テストスイート)を作成するための関数。
テストスイートとは、テストケースをまとめた単位。
describe(テストスイートの説明, テストスイートの実行するコールバック関数)
test
単一のTest Case(テストケース)を定義するための関数
test(テストケースの説明, テストケースの実行するコールバック関数)
describe('足し算引き算のテスト', () => {
test('足し算', () => {
const result = add(2, 3);
// 期待値(result)は「5」になるよねって意味
expect(result).toBe(5);
})
test('引き算', () => {
const result = subtract(5, 2);
expect(result).toBe(3);
})
})
セットアップ
beforeEach
各テストケースが動く前に実行されるコードブロックを定義
各テストケースが動く前に新しいインスタンスが初期化され、テスト間で状態が共有されないようになる
describe('合計が正しいこと', () => {
let calculator;
beforeEach(() => {
calculator = new Calculator();
});
it('足し算', () => {
expect(calculator.add(2, 3)).toBe(5);
});
afterEach
各テストケースが動いた後に実行されるコードブロックを定義
これにより、各テストケースは独立して実行され、カウンターの初期状態が保持されることが保証
describe('カウント', () => {
let counter;
beforeEach(() => {
counter = new Counter();
});
afterEach(() => {
counter.reset();
});
結果比較:Matcher(マッチャー)
マッチャーを使用することでテストの結果を期待値と比較し、テストの成功または失敗を判断する。
使用方法
expect(2 + 2).toBe(4);
種類
関数 | 説明 |
---|---|
toBe | 厳密な等値性を検証 |
toEqual | 値の内容を比較。(オブジェクトなどで用いられる) |
toBeTruthy | 値が真の値(truthy)であることを検証 |
toBeFalsy | 値が偽の値(falsy)であることを検証 |
toBeNull | 値がnullであることを検証 |
toBeUndefined | 値がundefinedであることを検証 |
toBeDefined | 値がundefinedでないことを検証 |
toContain | 配列や文字列が特定の要素を含んでいることを検証 |
toBeLessThan | 値が指定した値より小さいことを検証 |
toBeGreaterThan | 値が指定した値より大きいことを検証 |
toHaveBeenCalledTimes | 引数の数分関数が呼ばれたか確認 |
toHaveBeenCalledWith | 引数が期待値通りの引数か確認 |
他にもあるお。
Mock(モック)
テスト中に関数やモジュールの振る舞いを模擬するために使用
流れ
モジュールをimport → モック → モック関数の返す値を設定 → 呼び出し確認
// calculate.test.js
import { calculate } from './calculate';
import * as math from './math';
// mathモジュールをモックする
jest.mock('./math');
test('calculate関数のテスト', () => {
// add関数をモックする
// モック関数が返す値を10に設定
math.add.mockReturnValue(10);
// subtract関数をモックする
math.subtract.mockReturnValue(5);
// calculate関数を呼び出す
const result = calculate(3, 2);
// 期待する結果は (10 * 5) = 50
expect(result).toBe(50);
// add関数が呼び出されたかを検証
expect(math.add).toHaveBeenCalledWith(3, 2);
// subtract関数が呼び出されたかを検証
expect(math.subtract).toHaveBeenCalledWith(3, 2);
});
実際にやってみて引っかかったところ
値を変更する処理はact内で行う
問題
下記エラー発生orz
console.error
Warning: An update to TestComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
解決
割と基礎的なことでした。ユーザの操作イベントは、act内で実行しないとエラーが出ます。
以下が公式ドキュメントに記載されていたものです。
act(...) 関数はテスト中にユーザーインターフェースを更新するイベント(ユーザーのクリックや入力など)をシミュレートする際に使用すべき
// Act:検索リセット
act(() => {
xxx.onChangeSearch({
...condition,
});
});
API実行処理がある場合は、更新を待たないといけない
問題
API通信を含んだカスタムフックのテスト時、全然期待値通りにならない・・・????
解決
waitForNextUpdate関数で更新を待ちましょう。そしたら更新(または取得後)の値が 反映されるはずです。
const {result, waitForNextUpdate} = renderHook(() => useCounter())
if ('APIテスト', async() => {
省略・・・・・・
act(() => {
result.current.onSubmit();
});
await waitForNextUpdate(); // ここで更新を待つ
省略・・・・・
参考記事
Discussion