自動テストを使用してレガシーコードを改良するためのベストプラクティス


22

比較的大きくて古いコードベースで、既に定義されているインターフェイス(C ++ヘッダーファイルのセット)を再実装するタスクを引き受けようとしています。これを行う前に、可能な限り完全なテストカバレッジを取得したいので、再実装エラーをできるだけ早く簡単に検出できます。問題は、既存のコードベースが、(非常に)大規模なクラスと関数、高度な結合、(多くの)副作用を伴う関数などで簡単にテストできるように設計されていないことです。

同様のタスクの以前の経験や、自動化されたテスト(ユニット、統合、回帰など)をレガシーコードにどのように改良したかについての良い具体的なヒントを聞いていただければ幸いです。


1
ステップ1:スタックオーバーフローを検索します。質問がされました。何回も。
S.Lott

回答:


20

まず、Michael Feathersによる「レガシーコードを効果的に使用する」を入手して読んでください。これは、このようなタスクに不可欠な支援です。

次に、いくつかのメモ:

  • インターフェイスの正確な仕様/契約を持っていますか、または実際に「仕様」として既存の実装のみを持っていますか?前者の場合、最初から完全に書き直す方が簡単であり、後者の場合は不可能です。
  • インターフェイスを再実装する場合、テストリソースを費やす最も便利な方法は、インターフェイスに対してのみテストを作成することです。もちろん、これは厳密な意味での単体テストではなく、機能/受け入れテストではありませんが、私は純粋主義者ではありません:-)ただし、これらのテストは再利用可能で、2つの実装の結果を並べて直接比較できます。
  • 全体的に、完全に維持できない場合を除き、ゼロから書き直すよりも既存のコードをリファクタリングする方がよいでしょう。(しかし、この場合、どうやってそれに対して単体テストを書くつもりですか?)主題に関するより詳細な議論については、Joelからのこの投稿をチェックしてください。インターフェイスに対する一連の受け入れテストを作成すると、薄くても便利なセーフティネットが得られ、既存のコードをユニットテスト可能にするために慎重にリファクタリングを開始できます(Feathersの本のアイデアを使用)。

できればこれを+3します。WELCは不可欠な読み物であり、間違いなくリファクタリングに行く
...-Johnsyweb

2番目の点に関するマイナーなコメントの1つは、レガシーシステムの場合、テストは特性テストの考え方に従って行われるべきであるということです。つまり、ソフトウェアの現在の動作を忠実にキャプチャし、単体テストの考え方に従ってテスト結果の一部が奇妙に思われたり同意できなかったとしても、動作を変更しないようにします。(ところで、この考えはWELCの著者からも出ています。)
rwong

@rwong、確かに。詳細な仕様または知識のある製品所有者がいない場合、開発者はプログラムの特定の動作が意図的で必要か、b)意図的ではないが、今ではユーザーがそれに依存しているのか、c) d)これまでまったく気付かなかったバグ。最初の2つの場合、「修正」は実際にユーザーを傷つけ、最後の場合、修正は理論的には正しいものの目に見える利点を提供しません。
ペテルトレック

4

知っている最良の方法はミカド法です。http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ これは単純なテクニックの一般化にすぎませんが、大きなコードベースでコード品質の改善を開始する唯一の方法です不要なリスクを冒すことなく。

WEWLCも非常に優れた本ですが、C ++で書かれていることはJavaやRubyコードでは必ずしも有用ではありません。


2

古いコードベースへのレトロフィッティングテストは、設計がモノリシックであれば非常に困難です。

可能であれば(時間/お金がある場合)、前進するための1つの方法は、コードをよりテスト可能なユニットにリファクタリングすることです。


1

リンクを1つ追加したいと思います。テストが容易ではない実装が、よりxUnitフレンドリーなコードにリファクタリングされた例はほとんどありません。一般的なアプローチについては、すでに述べたリンクを試してください(Joel post、Working With Legacy code

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.