見出し画像

単体テストの考え方/使い方を読んで[2]

概要

単体テストの考え方/使い方をほぼ読み終わったので、テストコード1年経験者が学びになったポイントをかい摘んで書き残してみたい。
本全体の所感については[1] に記載

学びになったポイント

▼何をテストするか

結論、最終出力値のみをテストする。本書では外部から観察可能な振る舞いとも言い換えられている。
逆に、テスト対象のクラスが依存している別クラス(協力者オブジェクト)のメソッドの引数や戻り値などは検証しない。
ただしプロセス外依存は除く。例えばメソッドの戻り値だけでなく、アプリケーション外部へメッセージバスを通して出力するなども最終出力値の1つとして検証されるべきとある。このため最終出力値が複数存在する場合がある。

自分も恐らくそれがいいんじゃないかと思いつつ、あまり頭の中で整理出来ていなかったので明確な指針を得られた。
(※以降、古典学派の思想をベースとしている。学派については別途)

▼なぜ最終出力値なのか

メソッド内部で別のメソッドを呼び出して結果を得て、その結果を次のメソッドの引数として渡して処理をして、が幾つも続く場合がある。その場合も最終出力値である戻り値についてのみ検証すべきとある。
つまり道中のメソッド戻り値や引数について検証すべきではない。

理由としては、リファクタリング耐性が低くなってしまうから。
つまりテストが無駄に壊れて工数がかさみ保守性が悪いから。保守性が悪いだけならまだしも、保守も行われなくなると偽陽性が頻発し、テスト自体の信頼性が低まり、テスト検証のモチベーションも下がってしまう悪循環もある。

▼リファクタリング耐性とは

リファクタリングとは、コンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理することである。

wikipedia

リファクタリング耐性とは、動作(外部から見た際の最終出力値)を変えずにソースコードを整理出来る容易さ。耐性が高いほど容易に変更が行える。

リファクタリング耐性が低いとは、道中のメソッド戻り値や引数の検証を行うとリファクタリングが容易に行えなくなる、という意味になる。

この点は自分も経験したため強く同意出来る。
内部で幾つも依存したクラスがあり、それらで引き渡す引数が変わった場合にプロダクションコードは当然変更が入るが、テストの方も「メソッド呼び出しの引数修正」「新たな引数のテストデータの準備」などが必要になったりする。最終出力値が変わらない場合であってもテストが壊れてしまい、微妙に感じていた。

▼どうあるべきか

ブラックボックステストをすべきとある。

テストで検証したいこと「関心事」はテスト対象の最終出力値であって、道中の協力者オブジェクトにどんな引数が渡されてどんな出力があって、ということではない。
それらを詳細に検証することは、実装の詳細に依存しており、テストがすぐ壊れてしまう。

実装の詳細に依存した状態というのは、テスト対象をホワイトボックスで見ていて、中で何が起こっているか分かっている、また関心があるということ。
実装の詳細に依存していない状態というのは、テスト対象をブラックボックスで見ていて、箱に何を入れると何が出てくるかだけが分かる状態であり、こちらの方でテストをすべき。

箱の中の挙動がどうあるべきか詳細に検証しないため、中のコードをリファクタリングして変更してもテストが壊れることはない。
このことは良いテストのポイントの1つ「最小限の保守コストで最大限の価値を生み出す」に大きく寄与する。

あとがき

開発に掛けられる時間やコストは有限であり、単体テストの目標である、将来に渡ってプロジェクトの成長を持続可能にするには、テストがどうあるべきか指針を持つことの重要さを学んだ。

この記事が気に入ったらサポートをしてみませんか?