ここ数ヶ月ほど、ユニットテストを書くように努めている。と言うと、むしろ今まで書いていなかったのかとお叱りを受けそうだが、書いていなかった。今のプロジェクトは某社から引き継いだものだが、ユニットテストは書かれていなかった(ゼロではないが)。
例によって周囲に先達がいなかったので、自分で勉強して始めるしかなく、とにかくKent Beckのテスト駆動開発やらネット上の記事やらを読み漁りつつ、見よう見まねで始めたのだが、確かにユニットテストをすると、安心感がある。特に仕様の変更があった際、ユニットテストが異常検知してくれたケースもあった。
やってみてわかることもあるもんだ、と続けてみると、よいこともでてきたし、困ったこともでてきた。
ユニットテストはじめました
サービスの品質がまずい、というのはずっとわかっていた懸念事項だった。しかしテストにかけられる時間はよくあることだがあまりなく、しかもあらゆることをUIテストで行っていたから(たとえば入力文字数の制限チェックなど)、時間がかかって仕方がない。また、頻繁に起きる仕様変更(これはこれで問題なんだが)にもついていけていなかった。
なんとかしないといけない。そもそも、今やっているテストは本当にこれでいいのか?本当にこれで品質が管理できていると言えるのか?っていうかもうスクショ撮りたくない。意味があると思えない。僕は20代の頃レーダーシステムの試験をしていたことがあって、そのときに試験なるものについてたくさんのことを学べたのだが、このスクショ地獄は僕が知っている試験とは全然違う。テスターで数百の電源の電圧を測るだけのお仕事よりもつらい。
まぁソフトウェアにはソフトウェアのテストがあるのだとしても、これが最適なはずはない。調べていくと、テスト駆動開発、ユニットテストというキーワードにぶち当たる。これは使えそうだ、と思う。
しかし例によって、自分の周りには先達がいない。そもそもこのプロジェクト自体引き継いだもので、ちゃんとしたものであれば(ちゃんとしたものとはなんだ?いや、今それはいい)、ユニットテストだってきちんと書かれていたはずだ。が、現実はそうではない。つまり、頼りにできるのは自分だけだ。いつものことだ。
それで、Kent Beckのテスト駆動開発や、そもそもソフトウェアのテストとはいかにあるべきかとソフトウェアテスト自体についての入門書などを読み読みし、実践投入した。
ユニットテストの効果
見よう見まねではじめたユニットテストは、果たしてうまく書けているのかわからない、というか多分書けていない。しかし、そんな現状でもそれなりに効果は出ている。
まず、クラスの設計について今までよりよく考えることが多くなった。テストしやすいようにクラスを設計するのだが、テストしやすい、とはクラス設計の良い基準であると思った。このメソッドはどこまでの役割を担うべきなのか?コンストラクタでどこまですべきか?このクラスはつまりなんだ?テストできるように、と考えると、そういった問いが自然と出てくるし、またその答えも少しだけ明確になるように思う。というか、今までいかに適当に設計していたのか思いしらされたし、今後さらにそのことに気づくのだろう、、、と思うと気が重い面もある。それでも、今ここにいる自分がやるしかない……。
単純なミスが減った。プロパティの名前を間違えるという、信じられないミスをユニットテストで何度も気づかされた。今までであれば、UIテストの段階で予期せぬエラーとして発見されるか、最悪誰にも気づかれないまま本番で稼働することになっていた(実際、引き継いだプロジェクトのコードを読んで、まったく別のプロパティの値が表示されていた項目があることに気づいたこともある)。
仕様に変更が生じたとき、安心感をもってプログラムを書き換えられた。少なくともユニットテストはとおっている、という安心感は、やってみると大きなものだと思った。まぁ本当にそれで大丈夫かは、テスト次第なのだが。
UIテストを減らすことができた。バリデーションはユニットテストをすることで、すべてUIテストでまかなっていた時よりよくできている。
困っていること
新しいことを始めると、当然困ったことも起きる。
テスト自体がエラーを出し始めたこと。これは、ユニットテストの入出力がまずかった。ユニットテストの入力が、他のクラスの出力に依存していた。これじゃユニットじゃない。ユニットテストの出力が、データベースを汚していた。得られた教訓は、他人を頼らない、そしてゴミは片付ける。人生訓みたいだ。
インタフェース部分のテストが難しいこと。先のエラーの問題のも関連するが、そもそもデータベースに出力すること自体いいのか?と。しかし、REST APIでDBとの接続を受け持つようなコードでは、データベースに投げるところこそテストしたいことの一つだ。まぁその場合は、とにかくいったんデプロイし、統合テストとしてcurlでも投げて確認するのがよいのかなぁ……なんて考えている。
どこまでユニットテストでやるべきか悩む。文字入力であれば、バリデーションはユニットテストでやるべきだとしても、画面の振る舞いなんかは、どこまでやればよいのか悩む。上のインタフェースの問題のように、データの入出力についてのテストも悩む。
何をテストしてよいのかわからないこと。パブリックメソッドを実行してエラーがでないことを確認するだけのスモークテストが増え始めた。無いよりはマシかもしれないが、これではユニットテストをしていると胸を張って言えない……。僕もわかっているとは言い難いのだが、伝統的なソフトウェアテストの入門書を読んで、ホワイトボックステストや境界条件、有効同値・無効同値などの言葉とその意味を知るだけで、少しはなにか書けると思う。
ユニットテストをチームで行うこと。チームにユニットテストの経験がある人はいなかった。だから、ユニットテストの意義とそのための知識を共有する必要があり、ただでさえ時間のない業務において、これはたいへんなことだった。僕自身が勉強中の身の上、今も道半ばである。それでも今ここにいるチームでやるしかない。
一応はベンチャー企業で、一人エンジニア時代も長かった僕は、新たなエンジニアを雇うべくこれまで何人も面接をしてきたし、今もしているけれど、ユニットテストができる人はほとんどいない(提示する給与額の問題はあるにせよ……)。ネットを見ていると、ひょっとして僕以外の全員がユニットテストを完璧に書けるんじゃないのか?と思わせられるが、多分現実は違う。2019年この日本でユニットテストができる人材は、決して多くはないのだと思う。だから、できる人は自分の努力に自信をもっていいと思うし、そのスキルが得られた環境にも感謝すべきだと思う。そして僕に教えてください……。
参考書籍
参考にした書籍について。ネットにも良い記事は多くあると思うけれど、やはり断片的であるので、初学者はおとなしく書籍に頼ったほうがよいと思う。
テスト駆動開発をしようとする人で本書を知らない人はいないと思うが、TDDやXPのKent Beckの本。前半はJavaで、後半はPython。完全な理解にはほど遠いが、読まなくては始まらない。 ソフトウェアテストの入門書。そもそも何をテストすべきなのか?どこまでをユニットテストでやるべきなのか?を知るためには、ソフトウェアテスト全般の知識が必要。「知識ゼロから学ぶ〜」のほうが読みやすくわかりやすいが、「はじめて学ぶソフトウェアのテスト技法」のほうが網羅的。両方読んだらよいと思う。 読んでいる途中。どうせユニットテストを書くのであれば是非とも自動化したい。いつかはCIへ……。ソフトウェアテストにおける、ユニットテストの立ち位置を確認できる。 読んでいる途中。ユニットテストそのものについて、何を書けばよいのか。Javaは好かないが、考え方を知るために読んでいる。開発手法について書かれたKent Beckのテスト駆動開発よりも、ユニットテスト自体についてのヒントはこの本に多くあると感じている。 本書はサーバーレスなシングルページアプリケーションの開発についての入門書であり、ユニットテストについての本ではない。しかし、ユニットテストを当たり前のものとして使っているため。実際のアプリケーション開発において、ユニットテストがどのように使われるかを知るためによいと思った。とはいえ、サーバーレス、SPAに関心のない人がわざわざ読むものではない。
コメント