未テストまたはテスト不可能なコードをどのようにテスト/変更しますか?

StackOverflow https://stackoverflow.com/questions/7287

質問

最近、一部のコードに単体テストが含まれていない古いシステムのコードを変更する必要がありました。
変更を加える前にテストを書きたいのですが、各クラスによって多くの依存関係やその他のアンチパターンが作成され、テストが非常に困難になりました。
明らかに、テストを容易にするためにコードをリファクタリングし、テストを作成して変更したかったのです。
これはあなたならそうする方法ですか?それとも、リファクタリングが完了するとほとんど削除される、書きにくいテストの作成に多くの時間を費やしますか?

役に立ちましたか?

解決

初めに、 単体テストに関するヒントが記載された素晴らしい記事です. 。次に、古いコードに大量の変更を加えるのを避けるための優れた方法は、テストできるようになるまでコードを少しだけリファクタリングすることです。これを行う簡単な方法の 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 を使用できるため、これはやや悪い例ですが、最近似たようなケースでこれを実際に実行しました。ロードされるデータにまったく関係のない機能をテストしたかったためで、非常に効果的でした。また、このようにメンバーを公開することは、クラス内に長い間存在していた依存関係を取り除く必要がある他の同様のケースでも役立つことがわかりました。

ただし、フレームワークを作成している場合は、フレームワークのユーザーにメンバーを公開しても構わない場合を除き、このソリューションはお勧めしません。

ちょっとしたハックですが、とても便利だと思います。

他のヒント

@バルターズ

テストによってビルドが中断されるべきではないというあなたの意見には私は同意しません。テストは、テスト対象の機能に対してアプリケーションに新たなバグが導入されていないことを示すものである必要があります (バグが見つかった場合は、テストが欠落していることを示します)。

テストでビルドが中断されない場合、新しいコードがビルドを中断し、テストでカバーされていたとしても、しばらくの間そのことが不明になるという状況に簡単に遭遇する可能性があります。テストの失敗は、テストまたはコードを修正する必要があるという危険信号です。

さらに、テストでビルドが中断されないようにすると、失敗率がゆっくりと上昇し、信頼できる回帰テストのセットがなくなってしまいます。

テストが頻繁に中断されるという問題がある場合は、テストがあまりにも脆弱な方法 (DB ユニットを適切に使用しないデータベースや外部 Web サービスなど、変更される可能性のあるリソースへの依存) で作成されていることを示している可能性があります。あるいは、チーム内にテストに適切な注意を払わない開発者がいることを示している可能性があります。

コンパイルに失敗したコードをできるだけ早く修正するのと同じように、失敗したテストはできるだけ早く修正する必要があると私は強く信じています。

リファクタリングが完了したら単体テストが削除されるとなぜ言えるのかわかりません。実際には、単体テスト スイートはメイン ビルドの後に実行する必要があります (メイン製品のビルド後に単体テストを実行するだけの別の「テスト」ビルドを作成できます)。そうすれば、ある部分の変更が他のサブシステムのテストに影響を与えるかどうかがすぐにわかります。これは (一部の人が主張しているように) ビルド中にテストを実行するのとは少し異なることに注意してください。一部の限定的なテストはビルド中に役立ちますが、単体テストがたまたま失敗したからといってビルドを「クラッシュ」させるのは通常非生産的です。

Java を書いている場合 (おそらく)、チェックしてください。 http://www.easymock.org/ - テスト目的で結合を減らすのに役立つ場合があります。

『従来のコードを効果的に使用する』を読みましたが、これが「テスト不可能な」コードを扱うのに非常に役立つことに同意します。

一部のテクニックはコンパイル済み言語にのみ適用されます (私は「古い」PHP アプリに取り組んでいます) が、この本のほとんどはどの言語にも適用できると思います。

リファクタリングの本では、リファクタリング前にコードが半理想的な状態、または「メンテナンスを意識した」状態にあると想定していることがありますが、私が取り組んでいるシステムは理想的とは言えず、「使いながら学ぶ」アプリ、または使用される一部のテクノロジーの最初のアプリとして開発されました。 (私もその一人なので、そのことで初期開発者を責めるつもりはありません) そのためテストはまったくなく、コードは時々乱雑になります。他のリファクタリング本では通常 (まあ、ここまでではありませんが) 扱っていませんが、この本はこの種の状況について扱っています。

言っておきますが、私はこの本の編集者や著者から一切金銭を受け取っていません ;) しかし、レガシーコードの分野 (特に私の言語であるフランス語では、リソースが不足しているため) は非常に興味深いものだと思いました。別の話)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top