経緯
普段Vue.jsとdjangoを書いてるエンジニアです。テストしやすいコンポーネント設計を導入するか、どの程度適用するのかを決める際に、そもそもなんでテストするのか?について考える必要がありました。今回は、私がざっと考えてみたなぜ、テストが必要なのか?どの程度必要なのか?についてのざっくりとした考察記事です。
前置き
フロントエンドのテストって、意味わからないですよね。
デザインは頻繁に変わるし、画面数もとても多く、完全に統一された部品の再利用で作られたデザインでもなければ、全てをテストしきるのは本当に手間がかかるのに対して、見返りがとても少ないです。しかも、デザインが一新された場合、コンポーネントの作成・メンテナンスだけでも大変なのに、新しいのから、変更のあったコンポーネントテストも全てしなければならないとなると、到底テストをする工数の捻出から、モチベーションを続けるのは難しいでしょう。では、なぜフロントエンドでテストをするのでしょうか?UIが壊れていたって、なにか困ることがあるのでしょうか?テストしやすい設計なんて必要なのでしょうか?どれくらいテストすればよいのでしょうか?
TL;TD;
バグが起きたらインパクトの大きい箇所から順番にテストしましょう!
テストをする理由
サーバーサイドでテストをする理由
サーバーサイドでエラー・バグが発生した際に起きうる不都合な事をいくつか並べてみます
- 個人情報等、重要な情報の流出
- アプリケーション・会社の信頼性の低下
- 意図しない機能の実行
- 全体の機能が完全利用不可
- 特定機能が完全利用不可
- UXの低下
まだまだあると思いますが、ざっとこんなところでしょうか?
一応根拠のない優先度をつけてみました。
失敗
ではそれを踏まえた上で、とあるtoBサービスがテストコードを十分に書かないでリリースした場合の1つの失敗を可能性を例にしてみましょう。
バグった機能は個人チャット機能です。
原因
調べた所、送信対象のユーザーIDがintを要求しているのに、なぜかstringで渡されてしまって、型チェックで落ちてしまいました。しかし、チームは軽い気持ちでこの変更が含まれるコードをリリースしてしまいました。
症状
このサービスを利用していた全てのtoBが一時的に業務連絡が取れなくなってしまいました。このせいでサービスの信頼性が低下し、類似する他のサービスへユーザー移動してしまいました。
予防策
これは、etoeテストでレスポンスのステータスコード200番が帰ってくるかだけでも確認していれば、こんな単純なミスは防げたでしょう。まぁ、使用言語によっては、stringからintへ自動キャストされて200が通ってしまう場合もありますが、それは置いときましょう。
学び
今回は重大な機能ながらも、1機能の停止で済みましたが、もしormのdeleteの構文ミスで想定と違うレコードを削除してしまったりしていたら、目も当てられません。DBのレコードを追加・更新・削除する機能を持つモジュールは全てテストするべきです。この3つは取得よりも優先度がとても高いでしょう。データの取得は最悪バグっても、個人情報の流出以外なら、なんとかなる場合が多いです。
テスト優先度
今回の学びを活かして、テストする優先順位をつけるならこんな感じで大丈夫でしょう。
- 個人情報を取り扱う全ての機能
- 更新機能・削除機能・追加機能
- 取得機能
フロントエンドでのテスト
フロントエンドでテストをする理由
これは、サーバーサイドでテストをする理由と同じだと思います。
経験
そもそもモダンなフロントエンド技術で作成する大半のものは、データの表示でしょう。通信インターフェイスを利用し、色んなデータを加工したりして、装飾を付けて表示します。それらは、テスト優先度で言う所の3番目の優先度です。
大抵の装飾がバグったとしても、データに影響がないので困らないでしょう。勿論UXに影響はあるでしょうが、先程適当に付けたテストをする理由の中では、最も優先度の低い理由です。
フロントエンドのテストが大変な理由
フロントエンドでは、テストの優先度が特に重要になってきます。それは、テストがとても大変だからです。
なぜ大変かというと
- デザインの変更が機能の変更と比べて、頻度が高い
- 作成されるコンポーネントの粒度がバラバラだから、同じ経験則でのテストができない
- 全体の機能を一新しよう!という事は基本ないのに、デザインを一新しよう!は全然ある。ページが20ぐらいあったならば、テストするコンポーネントは100は行くでしょうか?デザインによりますね。
- 単純な関数をテストする際のin outとは違い、リッチなコンポーネントでは状態がとても多く、しかもコードを読むのが辛い。まるでサーバーサイドにクラスが100個ぐらいあって、それらをテストするのに近い。しかも変化にはアニメーションやら非同期が含まれる。
ざっとこんなものでしょうか?
フロントエンドでのテストの優先順位付け
どこからテストすれば良いでしょうか?
当然ですが、個人情報に関わる全てのコンポーネントでしょう。個人情報は特別ですので、それを除いた場合を考えましょう。
それは、追加(post)・更新(put)・削除(delete)です。htmlで実現する場合、form要素を使うことになるでしょう。つまり、formのテストが基本的には優先度が高いでしょう。
テスト作成ストーリー
- 個人情報に関わる全てのコンポーネントのテストを作ります。
- サービスのコアの機能となるFormからテストを作ります。
- 残りの表示用コンポーネントのテストをします。
まとめ
バグが起きたらインパクトの大きい箇所のテストから作成していきます。そのインパクトの大きさは、テストをする理由の指標を用意し、当てはめたら大体わかるでしょう。
指標を作成する際には、テストをする理由の指標をポイントとセットで用意し、この段階ではこの閾値以上のポイントを持つコンポーネントのテストをすると決めると良いでしょう。そうすれば、そのコンポーネントはテストしなければならないとわかり、コンポーネントに当てはめるパターンを決めれます。すると、そのコンポーネントを作成するのに必要な工数も、前よりは大分正確に見積もれる副産物もあります。また、テストする優先度がとても低いコンポーネントは雑に作っても問題ないとわかります。もちろん、クオリティを追求した方が技術的にはよいでしょうが、開発速度とのトレードオフがあることを、理解しなければなりません。
最後に
初めにテストしやすい設計が必要?という問いに関しての解は、当たり前ですが、コンポーネントによる、でしょうか。
テストはとても大変でしょうが、まずは個人情報等を操作するフォームから小さく初めてみてはいかがでしょうか?