「React コンポーネントってどこまで細かく分割していいの?」とか、「Jest のスナップショットテストテストってどんなテストにも使っていいの?」とか、技術的な落とし所をどうするか悩むことは結構多いと思う。
コンポーネントを分割すると、責務が小さくなったり、再利用しやすくなったり、変更に強くなったり、各種ツールから利用しやすくなったりと、色々なメリットが得られる。けど、だからといってコンポーネント分割のしすぎは良くないと思う。コンポーネント分割するとなると、(そのプロジェクトの規約によるけど) コンポーネントファイルを新しく作らないといけないし、CSS Modules 用の *.module.css
ファイルも作らないといけない。ファイルが増えることで、開発中に色んなファイルを行ったり来たりすることになって、作業効率が落ちる場合もある。コンポーネント分割だってタダじゃないし、デメリットもある。だからこそ、どこまでコンポーネント分割していくのか、その落とし所で悩むことになる。
こういう時に落とし所を探す方法はいくつかあるのだけど、id:mizdra はよく「極端なパターンを考える」というのをやっている。例えば「1タグごとにコンポーネント分割していったらどうなるか」とか。
function H2(props) { return <h2 {...props} /> } function Img(props) { return <img {...props} /> } function UserProfile({ useName, avatarUrl }) { return ( <H2>{userName}<H2/> <Img src={avatarUrl} /> ); }
見ての通り、コンポーネント分割したのに責務は小さくなっていないし、再利用しやすくなっていないし、変更にも強くない。コンポーネント分割のメリットが全く享受できていない。けどデメリットは被っている。「ああ、多分細かく分割しすぎたのだな」「メリットが享受できないパターンは NG なのだな」「ということは、責務が小さくなったり、再利用しやすくなると嬉しい場面で使っていくのが良いのかな?」「ロジックが沢山あるようなコンポーネントだったら責務小さくなって嬉しそうだし、色々なページで何回も出てくるようなパーツだったら再利用の効果が効いて良さそうだな」。そういった気づきが得られるはず。
あまりにも愚直なテクニックなのだけど、意外なことに、そこから芋づるのように技術的な落とし所のヒントが見つかってくる。色々な場面で使えるし、バカっぽいアイデアを考えるのが (そして信じられないことに、そのバカっぽいアイデアから気づきが得られるのが) 何より楽しい。オススメです。
実践例
以下の記事も今回紹介したテクニックを使って書きました。
- 出力の差分が巨大になる場合、スナップショットテストは向いてません
- 例: 2 京行の差分が出る時
- 例: Visual Regression Test で、5GB の画像が出力される時
- テストフレームワークが処理するのに時間が掛かるし、最悪の場合クラッシュします
- 出力の差分を見て、その妥当性を判断するのが困難な場合、スナップショットテストは向いていません
- 例: 5 万行の差分が出るテスト
- 1 分で 50 行見たとしても見終わるのに 1000 分掛かります
- 9 時に出社して差分を見始めて、お昼過ぎてもまだまだで、定時過ぎてもまだまだで、終電が無くなった頃にようやく見終わる、みたいなスケール
- 機械より人間が頑張るスタイル
- ただし差分の内容を見ずに変わったことだけ分かれば良い場合や、最初の 100 行だけ見て妥当ですねと判断できる場合であればこの限りではないです
- 出力の変化が激しい場合
- 例: 現在時刻を表示するクロックコンポーネントのテスト
- テストを実行する時刻によって出力が変わって毎回テストが fail します
- 毎回人の目でチェックしないといけません
- 機械より人間が頑張るスタイル 2
- ただし何らかの手段で出力を固定できれば、問題を回避できる場合があります
- クロックコンポーネントの例では時間を司る API をモックして時刻を固定すれば良い
- Visual Regression Test なら変化する部分を黒塗りしてから比較すれば良い
- このような出力の固定化が困難な場合はスナップショットテスト以外のテスト手法を検討しましょう
- 例: アプリケーションのソースコードそのもののスナップショットテスト
- ソースコードを 1 文字書き換えたらテストが fail する、みたいな
- 誰もそんなテスト書かないと思いますが…
- 良い具体例が思いつかなかった!本当はちょっとどこかを弄ったら毎回 fail するのは良くないよね、みたいなことを言いたかった。