Open5

Reactのテスト入門

jestチュートリアルやってみる

最初のsum関数を作るサンプル

sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;
sum.test.js
const sum = require("./sum");

test("add 1 + 2 equal 3", () => {
  expect(sum(1, 2).toBe(3));
});

実行

yarn test
yarn run v1.22.10
$ jest
 PASS  ./sum.test.js
  ✓ add 1 + 2 equal 3 (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.308 s, estimated 1 s
Ran all test suites.
✨  Done in 1.11s.

expectの値(sum(1,2))とtoBeの値(3)が同じかテストした。
toBeみたいなやつをマッチャーと呼び様々なものがあるらしい

一般的なマッチャー

https://jestjs.io/ja/docs/using-matchers

コンポーネント思考のテストの方針

参考見した記事

https://qiita.com/noah-nao/items/3fd211deb8711fae8204
https://zenn.dev/seya/scraps/6f930e359d6a7c

リファレンス

フロントエンドテストのコンセプト(kent C Doddsの考え)

「壊れるべき時に壊れてくれて、壊れるべきでない時に壊れないでくれるテスト」

テストの種類

  1. E2E
  • ブラウザ環境で本格的なユーザーフローをテストする。(Cypress)
  1. Integration
  • コンポーネント間の相互テスト(Jest、Mocha)
  • それを保管するテストユーティリティとしてTesting Libraryなどがある
  1. Unit
  • 単一のコンポーネントor機能のテスト
  • ツールはIntegrationと同じものを使うことが多い
  1. Static
  • 型やLinterによる静的チェック(TypeScript、ESLint)

Testing Trophy

kent C Doddsの提唱するテスト方針のコンセプト

Image from Gyazo

上側にあるテスト(最上部はE2E)ほど、

  • テスト実行時間:遅い(☓BAD)
  • テストの保守運用工数:高い(☓BAD)
  • システムの正常さの保証レベル:高い(○GOOD)

実際の運用の比率としては、画像の体積を目安とすると良いらしい。

  • Integrationが一番大きい
  • 次はE2EとUnit
  • Staticは問答無用で導入して、コストはかけない

テストの方針

  1. 「実装の詳細」をテストしない
  2. 外部システムに依存するテストをしない
  3. モックはできる限り少なくする
  4. 「コードカバレッジ」より「ユースケースカバレッジ」を意識する

「実装の詳細」をテストしない

参考:

https://kentcdodds.com/blog/testing-implementation-details

「実装の詳細」= 「ユーザーから見えないもの」

// ユーザーから見えないもの(実装の詳細→テストで操作したらダメ❌)
- State
- Component内の関数

// ユーザーから見えるもの(テストで操作してOK⭕️)
- UI(表示されるテキストなど)

「実装の詳細」をテストしない理由

  • 「壊れるべきでない時に壊れる」
  • 「壊れるべきでない時に壊れない」

今両方が起きてしまうから

「壊れるべきでない時に壊れるテスト」

リファクタリング = ユーザーからの見た目を変えずに、実装の詳細を変える行為
→ 詳細部分のテストすると、詳細部分はリファクタリングで変更され、壊れるべきでないのに壊れる!!

なので、「実装の詳細」はテストしないべき!

「壊れるべきでない時に壊れないテスト」

詳細のテスト = 機能単位でのテスト
結合テストのような、実際のアプリ全体が連動する事で起き得る挙動で、テストがエラーを返せない場合がある!

なので、「実装の詳細」はテストしないべき!

これを防ぐにはE2Eなどのテストも書いて全体のテストも実行すべき

ユニットテストより、インテグレーションテストを書く

Testing Trophyで触れた比重通りIntegrationに一番重きを置く

ReactなどでIntegratinはページ全体のテストなどが多い

【GOODなテストの例⭕️】
ユーザーがボタンをクリックしたときの挙動を再現し、表示がAからBに変わったことをテストする。

(この処理の途中にどんなメソッドが動いているかなどは気にせず、
ユーザーから見える部分のみ操作、テストしている。
そのため表示をA→Bに変える内部メソッドをリファクタで消したとしても、
ユーザーに見える部分が変わらなければテストは壊れない)


【BADなテストの例❌】
表示をAからBに変えるメソッドを直接ユニットテストする。

(ユーザーが見ることのない内部メソッドを直接テストしている。
この場合このメソッドをリファクタするとこのテストが壊れてしまう)

Snapshotoをむやみに使わない

Snapshot = 「実装に詳細」である事が多い

外部システムに依存するテストはしない

外部システムとの通信は可能な限りモックに置き換え、モックのメソッドの「呼び出し回数」と「呼び出し時の引数」でテストをする

「モック」はできるかぎり少なくする

とはいえモックはモックで実際のアプリではないので、システムが正しく動く保証は使えば使うほど下がる

「コードカバレッジ」より「ユースケースカバレッジ」を意識する

タイトル通り
コードカバレッジの目標値を追い求めるテストではなく、ユースケースを意識して

ログインするとコメントできます