Atomic Designでのテストを考える【初級】

## 概要

初Atomic Designを導入して開発をしてて、どこにどうやってテスト書けばいいんだっけ？　という旨の備忘録です。

### 仕様言語とかツールとか

- TypeScript
- React+Redux
- redux-saga
- Jest
- AtomicDesign

※Atomic Designの説明はしません（Atomic Designの説明は[こちら](https://blog.spacemarket.com/code/atomic-design%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6react%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E5%86%8D%E8%A8%AD%E8%A8%88%E3%81%97%E3%81%9F%E8%A9%B1/)が分かりやすいです）

※超初歩&限定的な内容な気がするので、書いてないメソッドやパターンについては適宜調べていただけると嬉しいです

## 概要

Jestを使います。

- やること
    - インタラクションテスト
    - ロジックテスト

- テスト対象
    - AtomicDesignにより分類された各コンポーネント
        - 本記事での例題はatomsのButton
        - インタラクションテストする
    - Reducer
        - ロジックテストする
    - 対象外
        - middleware
        - 別途書く予定です



## Jestって？

- 公式HP

[Jest · 🃏快適なJavaScriptのテスト](https://jestjs.io/ja/)

> ゼロ・コンフィギュレーションのテストプラットフォーム
> 
>Facebook において、Jest は Reactアプリケーションを含む全ての JavaScriptコードのテストに利用されています。Jest の哲学の１つは統合的な"ゼロ・コンフィギュレーション"体験を提供することです。エンジニアがすぐに使えるツールが与えられることで、より多くのテストを作成し、その結果としてより安定的で健康的なコードベースに繋がることを目の当たりにしてきたのです。（公式HPより）

Reactでのテストは、だいたいJestを使ってる印象です。

## テストファイルの置き場所

テストファイルの置き場所は2通りあります。

- `__tests__` フォルダにテストを格納する

または

- テストのファイル名に`.spec.js`または`.test.js`拡張子をつける

上記のどちらかすれば、Jestが自動的に実行してくれます。

自分は、`__tests__`フォルダで統一してます。
併用は迷いの元なので、どちらかに決めちゃいましょう。

## インタラクションテスト

ユーザーイベントに伴う挙動のテスト。
ボタンをクリックしたら関数が実行されるか、など。

- 主にStatelessコンポーネントで行います。
    - Atomic Designで言うと、atomsとmoleculesが対象。
- EnzymeというJestのテストユーティリティを使います。

[Introduction · Enzyme](https://airbnb.io/enzyme/)

### 例:Buttonコンポーネントでクリックをコールバックする挙動をテスト

```フォルダ構成.
- Button
    - __tests__
        - index.test.tsx
    - index.tsx
    - style.css
    - style.css.d.ts
```

```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
```


```loginReducer.test.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等のテストを書く予定です。