こんにちは、今回からコラムを書かせていただく和田
現代のソフトウェア開発の対象領域は、広く複雑で不確実なものになりました。この連載では、自動テスト
初回のテーマは、学習や調査が目的のテストコードを書くテクニック
二兎を追わない
プログラミングのコツに、
未知の技術を使って問題を解決するコードを書こうとするとき、私たちは2つのものと同時に戦うことになります。未知の技術そのものと、その技術を使った問題解決の2つです。2つ以上のものを同時に取り扱おうとすると、プログラミングは暗中模索の状態に陥りがちです。
このようなとき取るべき手段は、大きいタスクを小さいタスクに分割し、1つずつ倒すことです。つまり、未知の技術、たとえばこれまで使ったことがないライブラリやフレームワークの使い方を学ぶという学習タスクと、その知見を使って自分の解きたい問題を解決するタスクに分けるのが王道です。
即時性と再現性── 学びを支える2つの性質
未知の技術を学ぶときは、公式のドキュメントを読むだけでなく、実際に手を動かしてみることが効果的です。学びの効果がさらに高まるのは、即時性のあるフィードバックが得られるときです。手の動かしやすさと即時フィードバックが得られるという観点では、REPL
学びという観点でもう一つ大事なのが再現性です。再現性とは、学習内容をどのくらい簡単に再現できるかどうかです。この観点では、対話的環境で動かしただけでは十分とは言えません。過去の学習内容を手もとで再現するのがやや面倒だからです。
そこで、学びを自動テストの形で残すという手法が有力な候補になってきます。そういった学習目的の自動テストを
対話的環境で学んだ内容を学習用テストに移植するのもお勧めです。再現性に問題を抱える対話的環境の弱点を学習用テストで補い、効率良く着実に学べます。
では実際の学習用テストの例を見てみましょう。リスト1は、PHPの日付関係の標準ライブラリを調べているときに私が実際に書いたテストコードです。
不変オブジェクトDateTimeImmutable
の使い方を調査し、add
メソッドに副作用がないことを実際にテストを書いて確認しています。PHPの公式ドキュメントから読み取れることを、実際に手もとで検証しようとした記録であるとも言えます。
学習用テストを書いて未知のライブラリの使い方を学んだら、次にその学んだ内容を使って本来自分の解きたかった問題を解決するコードを書いていけばよいのです。
疑念、疑問をテストにする
学習用テストでは、頭に浮かんだ疑念や疑問をテストコードとして書くことも効果的です。たとえば、リスト1に出てきたDateTimeImmutable
はタイムゾーンの情報も持っています。では、タイムゾーンが異なるものの、同じ瞬間を指しているDateTimeImmutable
のインスタンスどうしは等価とみなされるのでしょうか。設計としては、等価であるとみなされても、等価ではないとみなされても、どちらもそれなりの説得力がありそうに思えます。
こういう場合は実際にテストを書いて動かしてみるのが早いですね。リスト2のテストは成功します。つまり、DateTimeImmutable
はタイムゾーンが異なっても同じ瞬間を指していれば等価とみなすことがわかりました。たとえば、この振る舞いが公式ドキュメントにない暗黙の仕様である場合、将来予告なく変更されることもありえます。暗黙の仕様の学習用テストを残しておくと、そのテストの失敗が、過去学んだ振る舞いの変更を教えてくれます。
印を付けて見分ける
学び終わったテストが不要になることもあるでしょう。学習用テストはほかのテストと同一のディレクトリに作成することが多いですが、時間が経つと見分けることが難しく、不要になった学習用テストが残ってしまいがちです。
そこで、学習用テストには印を付けておくことをお勧めします。テスティングフレームワークによってはテストにマークやタグを付けられるものがあります。リスト1、2では、PHPUnitの@group
アノテーションを使っています。タグ機能がない場合は、テストメソッドの命名規則などで学習用テストと伝わる名前を使うのがよいでしょう。タグやテストの名前をヒントに、それが学習用テストならば消すという判断を後日行えます。
まとめ
今回は、学びをテストコードの形にする学習用テストを紹介しました。学習用テストには2つの長所があります。すぐに学びの結果が得られることと、学んだ内容の再現性が高いことです。皆様も、ぜひ学習用テストを書いてみてください。