この記事はTesting Technology Advent Calendar 2023の1日目の記事です。
本記事で伝えたいこと
単体テストを書くことが当たり前になってきた一方、まだテストの仕組みや文化が根付いていない組織もあるように感じます。そして、開発者においてもテストの書き方がわからない人、テストを書くことによる開発体験の向上を感じてない人、テストの上達の仕方がわからない人など多くいるように感じます。
本記事ではそういったまだ単体テストが好きになれていない開発者向けに、筆者のテストに対する姿勢がどのように変わってきたかを振り返る記事になります。この記事が何かのきっかけや参考になれば幸いです。
本記事の対象読者
- まだ単体テストが好きと言えない人
- 単体テストの良さがわからない人
- 単体テストを書きたいが書き方がわからない人
- 単体テストを上達したいと思ってる人
テストの書き方がわからない
エンジニアになったばかりの頃、機能実装することで精一杯で単体テストはほとんど書いていませんでした。というより、書き方が分かりませんでした。当時働いていた組織では単体テストを書くことをルールとしてはいたものの、プルリクでテストコードの中身までは見ることはなく、自動テストをCIなどで回していたわけでもなかったのでとりあえず書いておけばいいみたいな暗黙の風潮というか触れちゃダメみたいな感じがありました。
一応補足しておくとテストに関してレビューまでは実施されていませんでしたがプロダクションコードのレビューはしっかりされていました。テストコードを書くという文化はあったように思います。しかし、そのテストコードの質までは見れていませんでした。
一回CircleCIを導入してテストが全部パスしないとマージできないような仕組みもあったのですが、早々に破綻したように思います。
このように、テストに関してはそこまで言及されない環境だったため書いていたテストはほとんどコピペで既に存在するテストを持ってきて、テスト対象のクラスを変えるみたいな感じで書いていました。コピペでテストを書いているのでなぜテストを書くのかもわかっていません。とりあえず、書いていないと怒られるから書いてました。テストがあることでコードが正常に動くことの保証になるとも思ってませんでした。こんなモチベーションでテストを書いているとさまざまな辛みが発生します。
バグがあったときに言い訳できない
開発が終わってプルリクを出し、レビューが完了して、マージをしてデプロイまでさせたのにバグが発生してしまうことはよくあります。バグが発生してしまうのは仕方ないことです。ただ、バグを発生させないような努力をしたのかを問われることにはなります。まだ、単体テストを書いていれば「ケースが足りてなかったね」とかで済むかもしれないですが単体テストすら存在しないと大変です。言い訳できません。
組織として単体テストの仕組みが整備されていなかった部分もありますが、実装担当者として単体テストを適当に書いてデプロイまでしてバグが発生するのはメンタルに悪すぎました。
このような経験から筆者はとにかくバグを発生させないようやることは全部やりましたと自信をもって言えるようにテストは絶対書くようになったと思います。
(質の悪い単体テストは基本的に負債です。単体テストを書けばいいというわけではないですが書かないとテストは上手くならないとも思います。じゃあテストがまだ上手く書けない開発者はどうすればいいんだよという話になると思うのですがその話は一旦置いておきます。)
実装した機能が本当に正しく動作をするのかがわからない
単体テストがまともに書けないので自分が実装した機能が本当に仕様通りに動くのかがわかりませんでした。一応ローカルでは確認してるけど開発環境にあげて本当に動くのかというと自信が常になかったです。もはや神頼み
まだ、管理画面のようなweb画面の開発なら動作確認もしやすいですが、当時担当していたバッチ処理は手元で動かすみたいなのもなかなか難しく、単体テストがちゃんと書けてないと本当に動くのかがわからず、毎回心臓破裂しそうになりながらバッチ動かしてました。
自分が実装したものがちゃんと動くと自信を持つにはちゃんと単体テストを書く必要があります。ちゃんと単体テストを書くにはコピペではなく自分で何をどのような目的でテストすべきかを考えれないと書くことはできません。
テスト書くのを楽しいと感じる
単体テストを何も考えずにコピペで作成することがいかに愚かなのかを身をもって学んだため単体テストはよく思考して作成するようになりました。単体テストをちゃんと意識して書くようになってから事前にバグの存在に気づくことができ、単体テストを書いていてよかったと思うことが何回もありました。
2万行の単体テスト
あるAPI開発をしているときに巨大なJSONを扱っており、その全ての値をアサーションするようなテストをチーム全体で書いていたことがあります。何十、何百のケースで検証するためそのテストコードは2万行近くになりIDEでコードが開けなくなるほどでした。そんな膨大なケースの検証などまともにやってられるわけもなくプロダクションコードの動作を検証するようなテストではなくただただテストがパスするようなテストを作成していたように思います。
筆者はせめてコード量を減らそうとテスト内でループを回しテストケースを作成していましたが、当時のリーダーにパラメーターテストの存在を教えていただきました。
膨大な量のテストケースをパラメーターテストで綺麗に作成されていたリーダーのテストコードを見たときに「なんてスマートなんだ!!」と衝撃を受けたのを覚えています。
このことをきっかけにテストコードをいかに簡潔で短く書くかにこだわるようになり、いろいろ試行錯誤をするようになりました。失敗も多かったですが、いろいろ試行錯誤してより良いテストを探るこの時期は学びも多く、とても楽しい時期でした。
チームでテストの仕組みづくり
転職をし職場環境が受託からユーザー向けの自社サービスを扱う会社に変わりました。前職よりもいろいろと縛りやルールは緩く、提案したことはどんどん取り入れてくれるような非常に働きやすい環境でした。しかし、テスト環境というかテスト文化はあまり根付いていない環境ではあり、前職とのギャップを感じていました。
そこで、できる限りテストを書くことを推進できるよう今まで以上にテストをちゃんと書くようになりました。
テスト文化を作るためにやったこと
まず、単体テストを書くためのライブラリやツールを整備しました。テスティングライブラリやモックライブラリ、テスト用のDB環境の整備などを行い、とにかくテストが書けるようにしました。
そして、今までテストをちゃんと書いてこなかったチームで今日からテスト書いていきましょうと言ってもどう書いていいか困惑してしまうため、まずは自分だけでひたすらテストを書きました。最初はコピペでもいいのでテストを書くこと、興味を持ってもらえるようにするということを意図しました。
単体テストを書くという流れをなんとなくでも作った後は、作成した単体テストが容易にメンテナンスされなくなることを身をもって知っていたためCI上で自動テストを回す仕組みを作りました。
カバレッジなどの指標は一旦後回しにしました。
テスト文化を作るためにやったことの反省
上述の取り組みは0-1の新規立ち上げのサービスで行ったのですが、結果としてはうまく機能させることはできませんでした。機能の開発と変更のサイクルが多く、そのたびにテストが壊れてしまったため、テストコードのメンテナンスコストが非常に高くなってしまったからです。
CIの仕組みも作ってしまったために、壊れたテストがあると開発した機能を取り込むことができず、結果アンチパターンとして1番ありがちな作成したテストをコメントアウトするということになってしまいました。
テストを書くのにやらなければならないことはわかっていてもそれを実際に機能させることの難しさを知りました。
テストに関しての正しい知識を学ぶ
テスト駆動開発や単体テストの考え方/使い方などのテストについての知識をちゃんと学ぶことでなぜテストが機能しなかったのかということがなんとなくですがわかってきました。
テストの書き方がわからず、テストを書くことが目的になっているのは良いテストがなんなのかを知らないから。テストが壊れやすいのはリファクタリングへの耐性が低い設計であるため。
テストについての知識を学ぶとテストは開発手法だということがわかります。プロダクションコードの動作を担保するというのもありますがそれは副次的なものでテストを学ぶのは設計を学ぶことだと思います。
正しくテストが機能するようにするためにはテストや設計に関する正しい知識が不可欠なのかもしれません。
上述した技術書で学んだことを以下の本にまとめました。もし、興味を持っていただけた方は少しだけでもみていただけると嬉しいです🙌
まとめ
単体テストを書くことは現代の開発現場においては必須になってきたと感じます。しかし、これからはただテストを書くだけではなく質の良いテストを正確に理解し、質の良いテストを書くことが求められると感じています。
一方でテストに対してまだマイナスの印象を持たれている開発者も一定数いるのではないかと思っています。特に初学者はテストの必要性を真に理解するのは困難なようにも感じます。
初学者がテストを上達するにはどうすればいいのかはもし機会があれば考えてみたいなと思います。
雑に振り返った筆者のテストに対しての向き合い方でしたがどなたかのお役に慣れれば幸いです。
今回は以上です🐼