最近、すべてのコードに単体テストがあるわけではない古いシステムで、いくつかのコードを変更する必要がありました。
変更を加える前にテストを書きたいのですが、各クラスは多くの依存関係やその他のアンチパターンを作成し、テストが非常に困難でした。
明らかに、コードをリファクタリングして、テスト、テストの作成、および変更を容易にしたかったのです。
これがあなたのやり方ですか?それとも、リファクタリングが完了した後にほとんど削除される、書きにくいテストの作成に多くの時間を費やしますか?
4 に答える
まず、単体テストに関するヒントが記載されたすばらしい記事を次に示します。次に、古いコードに大量の変更を加えるのを避けるための優れた方法は、テストできるようになるまでコードを少しだけリファクタリングすることです。これを行う簡単な方法の 1 つは、プライベート メンバーを保護してから、保護されたフィールドをオーバーライドすることです。
たとえば、コンストラクター中にデータベースから何かをロードするクラスがあるとします。この場合、保護されたメソッドを単にオーバーライドすることはできませんが、DB ロジックを保護されたフィールドに抽出してから、テストでオーバーライドすることができます。
public class MyClass {
public MyClass() {
// undesirable DB logic
}
}
になる
public class MyClass {
public MyClass() {
loadFromDB();
}
protected void loadFromDB() {
// undesirable DB logic
}
}
そして、テストは次のようになります。
public class MyClassTest {
public void testSomething() {
MyClass myClass = new MyClassWrapper();
// test it
}
private static class MyClassWrapper extends MyClass {
@Override
protected void loadFromDB() {
// some mock logic
}
}
}
この場合はDBUnitを使用できるため、これはやや悪い例ですが、ロードされるデータとはまったく関係のない機能をテストしたかったので、実際に最近同様のケースでこれを実行したので、非常に効果的でした. また、このようなメンバーの公開は、クラスに長い間存在していた依存関係を取り除く必要がある他の同様のケースでも役立つことがわかりました。
ただし、フレームワークのユーザーにメンバーを公開することを本当に気にしない限り、フレームワークを作成している場合は、このソリューションに反対することをお勧めします。
ちょっとしたハックですが、とても便利だと思います。
@valters
テストがビルドを壊してはならないというあなたの声明に同意しません。テストは、テストされた機能に対して導入された新しいバグがアプリケーションにないことを示す必要があります(検出されたバグは、テストが欠落していることを示します)。
テストでビルドが中断されない場合は、新しいコードがビルドを中断し、テストでカバーされていてもしばらくはわからないという状況に簡単に遭遇する可能性があります。失敗したテストは、テストまたはコードのいずれかを修正する必要があることを示す危険信号である必要があります。
さらに、テストでビルドが中断されないようにすると、失敗率がゆっくりと上昇し、信頼できる回帰テストのセットがなくなるまでになります。
テストが頻繁に中断するという問題がある場合は、テストが非常に脆弱な方法で記述されていることを示している可能性があります(DBユニットを適切に使用していないデータベースや外部Webサービスなど、変更される可能性のあるリソースへの依存それはあざける必要があります)、またはテストに適切な注意を払っていない開発者がチームにいることを示している可能性があります。
失敗したテストは、できるだけ早くコンパイルできないコードを修正するのと同じように、できるだけ早く修正する必要があると確信しています。
レガシーコードを効果的に使用する方法を読みましたが、「テスト不可能な」コードを処理するのに非常に役立つことに同意します。
一部の手法はコンパイルされた言語にのみ適用されます(私は「古い」PHPアプリに取り組んでいます)が、本のほとんどはどの言語にも適用できると思います。
リファクタリングの本は、リファクタリングの前にコードが半理想的または「メンテナンス対応」状態であると想定することがありますが、私が取り組んでいるシステムは理想的とは言えず、「学習しながら学習する」アプリとして、または使用される一部のテクノロジーの最初のアプリとして開発されました。 (そして、私は彼らの1人なので、最初の開発者のせいにはしません)。したがって、テストはまったくなく、コードが乱雑になることがあります。この本はこの種の状況に対処しますが、他のリファクタリングの本は通常そうではありません(まあ、この程度ではありません)。
この本の編集者や著者からお金を受け取っていないことは言うまでもありませんが、レガシーコードの分野(特に私の言語であるフランス語)のリソースが不足しているため、非常に興味深いと思いました。別の話)。
リファクタリングが完了すると単体テストが削除されると言う理由がわかりません。実際には、単体テスト スイートはメイン ビルドの後に実行する必要があります (メイン プロダクトのビルド後に単体テストを実行する別の「テスト」ビルドを作成できます)。次に、ある部分の変更が他のサブシステムのテストを壊すかどうかをすぐに確認できます。ビルド中にテストを実行するのとは少し異なることに注意してください (支持する人もいるかもしれません) - 一部の限定的なテストはビルド中に役立ちますが、通常、一部の単体テストがたまたま失敗したという理由だけでビルドを「クラッシュ」させるのは非生産的です。
Java を作成している場合 (可能性は高い)、http: //www.easymock.org/ を確認してください。これは、テスト目的で結合を減らすのに役立つ場合があります。