概要
初Atomic Designを導入して開発をしてて、どこにどうやってテスト書けばいいんだっけ? という旨の備忘録です。
仕様言語とかツールとか
- TypeScript
- React+Redux
- redux-saga
- Jest
- AtomicDesign
※Atomic Designの説明はしません(Atomic Designの説明はこちらが分かりやすいです)
※超初歩&限定的な内容な気がするので、書いてないメソッドやパターンについては適宜調べていただけると嬉しいです
概要
Jestを使います。
-
やること
- インタラクションテスト
- ロジックテスト
-
テスト対象
- AtomicDesignにより分類された各コンポーネント
- 本記事での例題はatomsのButton
- インタラクションテストする
- Reducer
- ロジックテストする
- 対象外
- middleware
- 別途書く予定です
- AtomicDesignにより分類された各コンポーネント
Jestって?
- 公式HP
ゼロ・コンフィギュレーションのテストプラットフォーム
Facebook において、Jest は Reactアプリケーションを含む全ての JavaScriptコードのテストに利用されています。Jest の哲学の1つは統合的な"ゼロ・コンフィギュレーション"体験を提供することです。エンジニアがすぐに使えるツールが与えられることで、より多くのテストを作成し、その結果としてより安定的で健康的なコードベースに繋がることを目の当たりにしてきたのです。(公式HPより)
Reactでのテストは、だいたいJestを使ってる印象です。
テストファイルの置き場所
テストファイルの置き場所は2通りあります。
-
__tests__
フォルダにテストを格納する
または
- テストのファイル名に
.spec.js
または.test.js
拡張子をつける
上記のどちらかすれば、Jestが自動的に実行してくれます。
自分は、__tests__
フォルダで統一してます。
併用は迷いの元なので、どちらかに決めちゃいましょう。
インタラクションテスト
ユーザーイベントに伴う挙動のテスト。
ボタンをクリックしたら関数が実行されるか、など。
- 主にStatelessコンポーネントで行います。
- Atomic Designで言うと、atomsとmoleculesが対象。
- EnzymeというJestのテストユーティリティを使います。
例:Buttonコンポーネントでクリックをコールバックする挙動をテスト
- Button
- __tests__
- index.test.tsx
- index.tsx
- style.css
- style.css.d.ts
import { shallow } from 'enzyme';
import * as React from 'react';
import Button from './index';
describe('Button', () => {
it('クリックをコールバックする', () => {
// jest.fn()でmock関数を作成
// 実行された回数を自動で記録している
const click = jest.fn();
// shallow()関数に、テストしたいコンポーネントを第一引数として渡す
const wrapper = shallow(<Button onClick={click} />);
// クリックイベントを模擬実行する
wrapper.simulate('click');
// click.mock.calls.lengthでmock関数が実行された回数を取得している
expect(click.mock.calls.length).toBe(1);
});
});
ロジックテスト
主にreducers、middlewares、stateを持つコンポーネントで行います。
テストファイルの置き場所は、reducerフォルダ、middlewaresフォルダ内の__tests__
フォルダ内。
コンポーネントの場合は、コンポーネントフォルダ内。
例:organismsのログインフォームのReducerをテスト
- Reducer
- __tests__
- loginReducer.test.ts
- loginReducer.ts
//任意のactionを定義したファイルをインポート
import * as LoginFormActions from '../../actions/LoginForm';
// テスト対象のReducerファイルをインポート
import loginFormReducer from '../loginFormReducer';
// テスト項目をグループ化
// ここではloginFormReducerという名前で各テストをグループ化している
describe('loginFormReducer', () => {
// it('項目名', 関数)でテスト項目を定義
it('アクションタイプが"changeEmail"のとき、emailを更新する', () => {
// 前提となるstateを定義
const state = { email: 'a', password: 'b', error: 'c' };
// どのactionを発行するか定義
const action = loginFormReducer(state, LoginFormActions.changeEmail('x'));
// 期待値を定義
const expected = { email: 'x', password: 'b', error: 'c' };
// actualの結果がexpectedと一致するかどうか判定
expect(action).toEqual(expected);
});
});
本記事で扱うのはここまで。
次回はredux-saga等のテストを書く予定です。