アプリのテスト スーツがあります。テスト スーツが有機的に成長するにつれて、テストにはリファクタリング可能な反復コードが多数含まれます。
ただし、リファクタリングによってテスト スイートが変更されないようにしたいと考えています。私のテストがリファクタリングで不変であることをどのようにテストできますか。
(私はPython + UnitTestを使用しています)が、これに対する答えは言語に依存しないと思います。
アプリのテスト スーツがあります。テスト スーツが有機的に成長するにつれて、テストにはリファクタリング可能な反復コードが多数含まれます。
ただし、リファクタリングによってテスト スイートが変更されないようにしたいと考えています。私のテストがリファクタリングで不変であることをどのようにテストできますか。
(私はPython + UnitTestを使用しています)が、これに対する答えは言語に依存しないと思います。
テストの実際のテストは、実動コードです。
テストコードのリファクタリングがテストに失敗していないことを確認する効果的な方法は、ミューテーションテストを実行することです。ミューテーションテストでは、テスト対象のコードのコピーを変更してエラーを導入し、テストでエラーが検出されることを確認します。これは、一部のテストカバレッジツールで使用される戦術です。
私はそれを使用していません(そして私は実際にはPythonコーダーではありません)が、これはPython Mutant Testerによってサポートされているようですので、一見の価値があるかもしれません。
Coverage.py はあなたの友達です。
リファクタリングするすべてのテストを「システム テスト」(またはそのようなタグ) に移動します。必要なテストをリファクタリングし (ここで単体テストを行っているはずですよね?)、カバレッジを監視します。
理想的なケースでは、カバレッジは同じかそれ以上ですが、古いシステム テストをスラッシュできます。
FWIW、py.test は、テストに簡単にタグを付けて特定のテストのみを実行するためのメカニズムを提供し、unittest2 テストと互換性があります。
興味深い質問です。私は、「テストをどのようにテストするのですか?!」というタイプの議論を常に聞きたいと思っています。上記の@markswebからの良い点も。
テストが実際にやりたいことを実行し、意図したことをテストしていることを確認することは常に困難ですが、これを正しく行い、適切に実行することは良いことです。私は常に、プロジェクトの時間的制約、プレッシャー、必然的に発生する問題に関係なく、どのプロジェクトでもテストが開発作業の 1/3 を占めるべきであるという経験則を考慮しようとしています。
プロジェクトを継続して成長させるつもりなら、あなたが言うようにリファクタリングを検討しましたが、将来の機能の追加やプロジェクトの一般的な拡張のテスト駆動開発 (TDD) を可能にする適切なテスト フレームワークを作成する方法でしょうか?
Pythonについて言及されましたが、Smalltalkでリファクタリングがどのように適用されるかについてコメントしたいと思います。最新のSmalltalk実装には、ソースコードを再構築するためにシステムブラウザに統合された「リファクタリングブラウザ」が含まれています。RBには、システムの動作と安定性の維持について質問した変換を動的に実行するための書き換えフレームワークが含まれています。これを使用する方法は、スコープ付きブラウザーを開き、リファクタリングを適用し、差分ツールを使用してコミットする前に変更を確認/編集することです。Pythonリファクタリングツールの成熟度についてはわかりませんが、Smalltalkコミュニティがこのような素晴らしいソフトウェアを入手するには、多くの反復サイクル(年)が必要でした。
DonRobertsとJohnBrantは、リファクタリングツールの標準として機能する最初のリファクタリングブラウザツールの1つを作成しました。いくつかのビデオがあり、ここにこれらの機能のいくつかを示しています。メソッドをスーパークラスに昇格させるには、Pharoでメソッドを選択し、リファクタリングして「プルアップ」メニュー項目を選択するだけです。ルールは、提案された重複したサブ実装者を検出し、実行前に削除するかどうかを確認できるようにします。リファクタリングの適用は、テストコードに関係ありません。
理論的には、テスト対象のオブジェクトを実際にモックして、テスト用のテストを作成することもできますが、それは多くの作業を行うための方法であり、価値がないと思います。
したがって、残っているのはいくつかの戦略です。これは役立ちますが、これをフェイルセーフにすることはできません。
非常に注意深くゆっくりと作業してください。人為的エラーの可能性を制限するために、IDEの機能を可能な限り使用してください。
ペアで作業します。あなたの肩越しに見ているパートナーは、あなたが見逃したグリッチを見つけるかもしれません。
テストをコピーしてから、リファクタリングします。完了したら、本番コードにエラーを導入して確認し、両方のテストで同じ(または同等の)方法で問題を検出します。その後、元のテストを削除します。
最後のステップはツールで実行できますが、Pythonフレーバーはわかりません。検索するキーワードは「ミューテーションテスト」です。
そうは言っても、私はステップ1+2に個人的に満足しています。
テストスイートをリファクタリングしないでください。
リファクタリングの目的は、「コードの良さ」という抽象的な基準を満たすのではなく、コードの保守を容易にすることです。テストコードは優れている必要はなく、繰り返しを避ける必要もありませんが、徹底する必要があります。有効なテストができたら(つまり、テスト対象のコードで必要な条件を実際にテストします)、それを削除したり変更したりしないでください。したがって、テストコードをまとめて保守するのは簡単である必要はありません。
必要に応じて、既存のテストを書き直して、古いテストに加えて新しいテストを実行することもできます。これにより、新しい結合されたテストスイートが、古いテストスイートで発生したすべてのエラーを確実にキャッチします(将来、新しいコードを拡張すると、さらに多くのエラーが発生する可能性があります)。
テストが無効と見なされる方法は2つあります。テストが間違っていることに気付く(つまり、テスト対象のコードが正しい場合に誤って失敗することがある)か、テスト対象のインターフェースが変更されている(テスト対象のAPIを削除する、または動作を許可する)以前はテストの失敗でした)。その場合、スイートからテストを削除できます。多数のテストが間違っていることに気付いた場合(重複したコードが間違っているため)、それらをすべて削除して、リファクタリングおよび修正されたバージョンに置き換えることができます。ソースのスタイルが気に入らないという理由だけでテストを削除することはありません。
特定の質問に答えるには、新しいテストコードが古いコードと同等であることをテストするには、(a)すべての新しいテストが現在の既知のコードベースで合格していることを確認する必要があります。 、これは簡単ですが、(b)新しいテストは、古いテストが検出するすべてのエラーを検出します。これは、テスト対象のコードの一連の誤った実装が手元にないため、通常は不可能です。
テスト スイートをリファクタリングする簡単な方法がわかりません。リファクタリングの範囲によっては、明らかにテスト スイートを変更する必要があります。テストスイートの大きさは?
適切にリファクタリングするには、時間と細部への注意が必要です (そして、多くのCtrl+ C Ctrl+ V!)。テストをリファクタリングするときはいつでも、リスクが多すぎるため、検索と置換以外の簡単な方法を見つけようとはしません。
テストの品質を維持したい場合は、ゆっくりではありますが、適切に手動で行うのが最善です。
テスト コードは、合格して正しいものである限り古くならないため、API の低レベルのドキュメントとして最適です。しかし、ごちゃごちゃしたテスト コードは、その目的を十分に果たせません。したがって、リファクタリングは不可欠です。
また、テストされたコードは時間の経過とともに変化する可能性があります。テストも同様です。それをスムーズにしたい場合は、コードの重複を最小限に抑える必要があり、可読性が重要です。
テストは読みやすく、常に一度に 1 つのことをテストし、次のことを明示する必要があります。
それが考慮される場合、テスト コードをリファクタリングすることはかなり安全なはずです。一度に 1 ステップずつ、@Don Ruby が述べたように、実稼働コードをテストのテストにします。
多くのリファクタリングでは、高度な IDE ツールに安全に依存できることがよくあります (抽出されたコードの副作用に注意している場合)。
適切なテスト カバレッジのないリファクタリングは避けるべきだという点には同意しますが、通常のコンテキストでは、テスト用のテストを作成することはほとんどばかげていると思います。