単体テストが好きになるまでを振り返る


この記事は[Testing Technology Advent Calendar 2023](https://qiita.com/advent-calendar/2023/testing-tech)の1日目の記事です。

## 本記事で伝えたいこと

単体テストを書くことが当たり前になってきた一方、まだテストの仕組みや文化が根付いていない組織もあるように感じます。そして、開発者においてもテストの書き方がわからない人、テストを書くことによる開発体験の向上を感じてない人、テストの上達の仕方がわからない人など多くいるように感じます。

本記事ではそういった**まだ単体テストが好きになれていない**開発者向けに、筆者のテストに対する姿勢がどのように変わってきたかを振り返る記事になります。この記事が何かのきっかけや参考になれば幸いです。

## 本記事の対象読者

- まだ単体テストが好きと言えない人
- 単体テストの良さがわからない人
- 単体テストを書きたいが書き方がわからない人
- 単体テストを上達したいと思ってる人

## テストの書き方がわからない

エンジニアになったばかりの頃、機能実装することで精一杯で単体テストはほとんど書いていませんでした。というより、書き方が分かりませんでした。当時働いていた組織では単体テストを書くことをルールとしてはいたものの、プルリクでテストコードの中身までは見ることはなく、自動テストをCIなどで回していたわけでもなかったので**とりあえず書いておけばいい**みたいな暗黙の風潮というか触れちゃダメみたいな感じがありました。

:::note info
一応補足しておくとテストに関してレビューまでは実施されていませんでしたがプロダクションコードのレビューはしっかりされていました。**テストコードを書くという文化**はあったように思います。しかし、そのテストコードの質までは見れていませんでした。
:::

一回CircleCIを導入してテストが全部パスしないとマージできないような仕組みもあったのですが、早々に破綻したように思います。

このように、テストに関してはそこまで言及されない環境だったため書いていたテストはほとんど**コピペ**で既に存在するテストを持ってきて、テスト対象のクラスを変えるみたいな感じで書いていました。コピペでテストを書いているので**なぜテストを書くのか**もわかっていません。とりあえず、**書いていないと怒られる**から書いてました。テストがあることでコードが正常に動くことの保証になるとも思ってませんでした。こんなモチベーションでテストを書いていると**さまざまな辛みが発生**します。

### バグがあったときに言い訳できない

開発が終わってプルリクを出し、レビューが完了して、マージをしてデプロイまでさせたのにバグが発生してしまうことはよくあります。バグが発生してしまうのは仕方ないことです。ただ、**バグを発生させないような努力をしたのか**を問われることにはなります。まだ、単体テストを書いていれば「ケースが足りてなかったね」とかで済むかもしれないですが**単体テストすら存在しない**と大変です。言い訳できません。

組織として単体テストの仕組みが整備されていなかった部分もありますが、実装担当者として単体テストを適当に書いてデプロイまでしてバグが発生するのは**メンタルに悪すぎました**。

このような経験から筆者はとにかく**バグを発生させないようやることは全部やりました**と自信をもって言えるようにテストは絶対書くようになったと思います。

（質の悪い単体テストは基本的に**負債**です。単体テストを書けばいいというわけではないですが書かないとテストは上手くならないとも思います。じゃあテストがまだ上手く書けない開発者はどうすればいいんだよという話になると思うのですがその話は一旦置いておきます。）

### 実装した機能が本当に正しく動作をするのかがわからない

単体テストがまともに書けないので自分が実装した機能が本当に**仕様通りに動くのかがわかりませんでした**。一応ローカルでは確認してるけど開発環境にあげて本当に動くのかというと**自信が常になかったです**。もはや神頼み

まだ、管理画面のようなweb画面の開発なら動作確認もしやすいですが、当時担当していた**バッチ処理**は手元で動かすみたいなのもなかなか難しく、単体テストがちゃんと書けてないと本当に動くのかがわからず、毎回心臓破裂しそうになりながらバッチ動かしてました。

自分が実装したものがちゃんと動くと自信を持つにはちゃんと単体テストを書く必要があります。ちゃんと単体テストを書くには**コピペではなく自分で何をどのような目的でテストすべきかを**考えれないと書くことはできません。

## テスト書くのを楽しいと感じる

単体テストを何も考えずにコピペで作成することが**いかに愚かなのかを身をもって学んだ**ため単体テストはよく思考して作成するようになりました。単体テストをちゃんと意識して書くようになってから**事前にバグの存在に気づくことができ**、単体テストを書いていてよかったと思うことが何回もありました。

### ２万行の単体テスト

あるAPI開発をしているときに巨大なJSONを扱っており、その全ての値をアサーションするようなテストをチーム全体で書いていたことがあります。何十、何百のケースで検証するためそのテストコードは**2万行**近くになりIDEでコードが開けなくなるほどでした。そんな膨大なケースの検証などまともにやってられるわけもなく**プロダクションコードの動作を検証するようなテスト**ではなく**ただただテストがパスするようなテスト**を作成していたように思います。

筆者はせめてコード量を減らそうとテスト内でループを回しテストケースを作成していましたが、当時のリーダーに**パラメーターテスト**の存在を教えていただきました。

膨大な量のテストケースをパラメーターテストで綺麗に作成されていたリーダーのテストコードを見たときに「なんてスマートなんだ！！」と衝撃を受けたのを覚えています。

このことをきっかけにテストコードをいかに**簡潔で短く**書くかにこだわるようになり、いろいろ試行錯誤をするようになりました。失敗も多かったですが、いろいろ試行錯誤してより良いテストを探るこの時期は学びも多く、とても楽しい時期でした。

## チームでテストの仕組みづくり

転職をし職場環境が受託からユーザー向けの自社サービスを扱う会社に変わりました。前職よりもいろいろと縛りやルールは緩く、提案したことはどんどん取り入れてくれるような非常に働きやすい環境でした。しかし、テスト環境というかテスト文化はあまり根付いていない環境ではあり、前職とのギャップを感じていました。

そこで、できる限りテストを書くことを推進できるよう今まで以上にテストをちゃんと書くようになりました。

### テスト文化を作るためにやったこと

まず、単体テストを書くためのライブラリやツールを整備しました。テスティングライブラリやモックライブラリ、テスト用のDB環境の整備などを行い、とにかくテストが書けるようにしました。

そして、今までテストをちゃんと書いてこなかったチームで今日からテスト書いていきましょうと言ってもどう書いていいか困惑してしまうため、まずは**自分だけでひたすらテストを書きました**。最初は**コピペでもいいのでテストを書くこと**、興味を持ってもらえるようにするということを意図しました。

単体テストを書くという流れをなんとなくでも作った後は、作成した単体テストが容易にメンテナンスされなくなることを身をもって知っていたためCI上で自動テストを回す仕組みを作りました。

カバレッジなどの指標は一旦後回しにしました。

### テスト文化を作るためにやったことの反省

上述の取り組みは0-1の新規立ち上げのサービスで行ったのですが、結果としては**うまく機能させることはできませんでした**。機能の開発と変更のサイクルが多く、そのたびに**テストが壊れてしまった**ため、テストコードの**メンテナンスコストが非常に高くなってしまった**からです。

CIの仕組みも作ってしまったために、壊れたテストがあると開発した機能を取り込むことができず、結果アンチパターンとして1番ありがちな**作成したテストをコメントアウトする**ということになってしまいました。

テストを書くのにやらなければならないことはわかっていてもそれを**実際に機能させることの難しさ**を知りました。

## テストに関しての正しい知識を学ぶ

[テスト駆動開発](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA-Kent-Beck/dp/4274217884)や[単体テストの考え方/使い方](https://www.amazon.co.jp/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%80%83%E3%81%88%E6%96%B9-%E4%BD%BF%E3%81%84%E6%96%B9-Vladimir-Khorikov/dp/4839981728)などのテストについての知識をちゃんと学ぶことでなぜ**テストが機能しなかったのか**ということがなんとなくですがわかってきました。

テストの書き方がわからず、**テストを書くことが目的**になっているのは**良いテストがなんなのかを知らないから**。**テストが壊れやすいのはリファクタリングへの耐性が低い設計**であるため。

テストについての知識を学ぶとテストは**開発手法**だということがわかります。プロダクションコードの動作を担保するというのもありますがそれは副次的なもので**テストを学ぶのは設計を学ぶこと**だと思います。

正しくテストが機能するようにするためにはテストや設計に関する正しい知識が不可欠なのかもしれません。

上述した技術書で学んだことを以下の本にまとめました。もし、興味を持っていただけた方は少しだけでもみていただけると嬉しいです🙌

https://zenn.dev/jy8752/books/73769005e6afa9

## まとめ

単体テストを書くことは現代の開発現場においては**必須**になってきたと感じます。しかし、これからはただテストを書くだけではなく**質の良いテストを正確に理解し**、**質の良いテストを書くこと**が求められると感じています。

一方でテストに対してまだマイナスの印象を持たれている開発者も一定数いるのではないかと思っています。特に初学者はテストの必要性を真に理解するのは困難なようにも感じます。

初学者がテストを上達するにはどうすればいいのかはもし機会があれば考えてみたいなと思います。

雑に振り返った筆者のテストに対しての向き合い方でしたがどなたかのお役に慣れれば幸いです。

今回は以上です🐼