M

テストを書きましょう。あまり多くなりすぎないように。主に結合テストで。

Sep 28, 2023

これは、Kent C. Dodds 氏のブログ記事であるWrite tests. Not too many. Mostly integration.を日本語訳してみたものです。

誤訳などあればIssueや PR を頂けると幸いです。


このブログ記事は、こちらでご覧いただける講演を記事にしたものです:

少し前に、Socket.ioの作者でありZeit.co(最近発表された多くの素晴らしいものを生み出している会社)のファウンダーでもあるGuillermo Rauch氏深いことをツイートしました

テストを書きましょう。あまり多くなりすぎないように。主に結合テストで。

これは短いにも関わらず深いことなので、掘り下げてみましょう。

テストを書きましょう。

そうです、ほとんどのプロジェクトでは自動化されたテストを書くべきです。時間に価値があるのならとにかくそうするべきです。 午前2時に電話をもらってバグを修正するよりも、テストによってローカルでバグを発見する方がはるかに良いです。 テストを書くことに時間を費やすと時間の節約になっていることに気づくことがよくあります。 作るものにかかる実装の時間は長くなるかもしれないし、そうじゃないかもしれないけど、私(や他の人)がそれを維持することに費やす時間はほぼ間違いなく節約できます。

テストを書くときに考えるべきことは、プロジェクトにバグがないか確信を持つことがどれだけできるかどうか、です。 TypeScriptESLintのような静的型付けツールやリントツールは驚くほどの信頼性をもたらすので、 もしこれらのツールを利用していないのであれば使ってみることを強くお勧めします。 とはいえ、強く型付けされた言語であってもテストがあるべきです。型付けやリントは、ビジネスロジックにバグがないことを保証できません。 そのため、良いテストスイートによって信頼性を高めることが出来ます。

あまり多くなりすぎないように。

私は、マネージャーやチームがアプリケーションに対する100%のコードカバレッジを義務としているのを耳にしたことがあります。 それは本当に良くない考えです。問題は、カバレッジが70%を優に超える状態になると、テストから得られるものが少なくなる(数字は私が科学的根拠なく出したものです。。)ことにあります。 なぜでしょうか?それは、常に100%を目指しているとテストする必要のないものまでテストすることに時間を費やすようになるのです。 それらは本当にロジックを全く持たないものです(バグがあればESLintやFlowで発見できます)。 このようなテストの維持は本当にあなたやあなたのチームの速度を低下させます。

また、テスト環境で再現困難な1行のコードの確認をするためだけに実装詳細をテストしていることに気づくこともあるでしょう。 アプリケーションが動いていることに十分な信頼性を得られず、リファクタリング時に速度低下を招くので、実装詳細をテストすることは 本当に 避けたいものです。 リファクタリング時にテストを修正することは、滅多にするべきではありません。

私のほとんど全てのオープンソースプロジェクトが100%のコードカバレッジであることに触れておくべきでしょう。私のオープンソースプロジェクトはさまざまな状況で再利用できる小さなライブラリーやツールばかり (壊れると利用している多くのプロジェクトで重大な問題を招きます)で、とにかく相対的に100%のコードカバレッジを得やすいものです。

主に結合テストで。

テストにはさまざまな種類があります(これについてはFluent Confにおける私の5分の講演をご覧ください:"What we can learn about testing from the wheel") それぞれにトレードオフがあります。自動テストについて話題にするとき最も一般的な3つのテストの形態は、単体、結合、そしてE2Eです。

こちらは、私のフロントエンドマスターズワークショップ"Testing JavaScript Applications"でのスライドです。

テストピラミッド

このテストピラミッドは、マーティン・ファウラー氏のブログGoogleのテストのブログから組み合わせたものです。

ここで示しているように、ピラミッドは下から上へ、単体、結合、E2Eの順になっています。 ピラミッドの上へ向かうほどテストの記述/実行に時間がかかり、実行/維持に(時間とリソースの面で)より高いコストがかかります。 これによって、単体テストへより多くの時間を割くべきということを示すものです。

ここで示されていないことは、ピラミッドの上へ向かうほど各テスト形態の信頼指数が高まるということです。より多くの利益を得られるのです。 つまり、E2Eテストは単体テストよりも遅くコストが高いものですが、アプリケーションが意図通りに動作していることに対してより大きな信頼をもたらします。

上記の通り、我々のツールはマーティン・ファウラー氏によるテストピラミッドのコンセプトの想定を超えたものになっています。”テストトロフィー”を作った理由がここにあります 🏆。

こちらは、結合テストの重要性をユーモラスに説明したものです。

コンポーネント<B />にpropeが渡らずに壊れる場合には、コンポーネント<A />cdのpropsを受け取るコンポーネント<B />をレンダリングするかどうかは問題ではありません。 そのため、これらの部品が独立して機能することを検証する単体テストを幾らか持つことは悪いことではないですが、それらが適切に連携して機能すること検証しないとあまり意味がありません。 そして、適切に連携して機能することをテストすることで、わざわざ独立して個別にテストする必要がないと気づくことが多々あるでしょう。

結合テストは、信頼性とスピード/費用とのトレードオフの間で素晴らしいバランスが保たれます。 そのため、ほとんど(全てではないけども)の労力をここに費やすことをお勧めします。

これに関して詳しくはTesting Implementation Detailsを読んでください。 テストの形態について詳しくは、Static vs Unit vs Integration vs E2E Testing for Frontend Appsを読んでください。

より多くの結合テストを書く方法

結合テストと単体テストとの境界線はやや曖昧です。とにかく、より多くの結合テストを書くのにできる最も大きなことはあまり多くのことをモックするのをやめることだと思います。 何かをモックすると、テストしているものとモックされているものの間の結合における全ての信頼を除去していることになります。 私は、モックが(異論もあると思いますが時に避けられないものだとも理解しています。 毎回テストで 実際に メールを送信したりクレジットカードで支払ったりはしたくないと思いますが、大抵の場合においてモックを避けることは可能あり、そうすることでより良くなるでしょう。

Reactを利用しているのであれば、シャローレンダリングもモックに含まれます。 より詳しくはWhy I Never Use Shallow Renderingを読んでください。

結論

ソフトウェアのテストが時間の無駄だと異論を唱える人はいないと思います。 最大の課題は、実装詳細をテストすることによる誤った信頼ではなく、 何をテストするべきか知り、それをどのようにして本当の信頼を得るテストとするかです。

この記事がお役に立てば幸いです。また自信を持ってアプリケーショを届ける目標が達成されることを祈っています!