さらに、包括的なテストスイートを絶えず変化するコードと同期させる必要があるのは苦痛のようです。ユニットテストスイートは、ソフトウェアが構築され、安定し、機能するようになると、メンテナンス中に非常に役立つ可能性があることを理解していますが、それはゲームの後半であり、TDDも早い段階で役立つはずです。
主要なアーキテクチャの変更が行われているこれらの初期の変更では、単体テストスイートを配置することのオーバーヘッドが感じられることに同意しますが、単体テストを使用することの利点はこの欠点をはるかに上回っていると思います。問題は精神的な問題であることが多すぎると思います。ユニットテストはコードベースの二級市民と考える傾向があり、それらをいじる必要があることに憤慨しています。しかし、時間が経つにつれて、私はそれらに依存し、それらの有用性を評価するようになり、コードベースの他の部分と同様に、それらをそれほど重要ではなく、保守や作業に値するものと考えるようになりました。
主要なアーキテクチャの「変更」は、本当にリファクタリングのみで行われているのでしょうか。ただし、リファクタリングのみを行っていて、テストが失敗し始めた場合は、どこかで機能を誤って変更した可能性があります。これは、ユニットテストがあなたが捕まえるのを助けることになっているものです。機能とアーキテクチャに同時に抜本的な変更を加える場合は、速度を落とし、その赤/緑/リファクタリングの溝に入ることを検討することをお勧めします。追加のテストなしで新しい(または変更された)機能はなく、リファクタリング中の機能(およびテストの中断)。
更新(コメントに基づく):
@Cybisは、リファクタリングによって動作が変更されてはならないため、リファクタリングによってテストが中断されてはならないという私の主張に対して興味深い反対意見を提起しました。彼の異議は、リファクタリングがAPIを変更するため、「ブレーク」をテストすることです。
まず、リファクタリングに関する標準的なリファレンスであるMartinFowlerのblikiにアクセスすることをお勧めします。ちょうど今、私はそれをレビューしました、そして、いくつかのことが私に飛び出します:
- インターフェイスのリファクタリングを変更していますか? Martinは、リファクタリングを「動作を維持する」変更と呼んでいます。つまり、インターフェイス/ APIが変更されると、そのインターフェイス/APIのすべての呼び出し元も変更する必要があります。テストを含めて、私は言います。
- これは、動作が変更されたことを意味するものではありません。繰り返しになりますが、ファウラーは、リファクタリングの定義は、変更が動作
を維持することであると強調しています。
これに照らして、リファクタリング中に1つまたは複数のテストを変更する必要がある場合、これをテストの「中断」とは見なしません。これは、コードベース全体の動作を維持するためのリファクタリングの一部にすぎません。テストを変更する必要があることと、リファクタリングの一部としてコードベースの他の部分を変更する必要があることの間に違いはありません。(これは、テストをコードベースの第一級市民と見なすことについて前に言ったことに戻ります。)
さらに、リファクタリングが完了すると、テストは、変更されたテストであっても、引き続き合格することを期待しています。そのテストがテストしていたもの(おそらくそのテストのassert(s))は、リファクタリングが行われた後も有効であるはずです。それ以外の場合は、リファクタリング中に動作が何らかの形で変更/後退したことを示す危険信号です。
その主張は意味がないように聞こえるかもしれませんが、考えてみてください。本番コードベースでコードのブロックを移動し、新しいコンテキスト(新しいクラス、新しいメソッドシグネチャなど)で引き続き機能することを期待することについては何も考えていません。テストについても同じように感じます。おそらく、リファクタリングによって、テストが呼び出す必要のあるAPI、またはテストが使用する必要のあるクラスが変更されますが、最終的には、リファクタリングのためにテストのポイントが変更されることはありません。
(私が考えることができる唯一の例外は、LinkedListをArrayListなどに置き換えるなど、リファクタリング中に変更する可能性のある低レベルの実装の詳細をテストするテストです。しかし、その場合、テストは過剰にテストされており、硬すぎて壊れやすいです。)