web-dev-qa-db-ja.com

コードを変更すると失敗する自動化された単体テストを作成する必要がありますか?

一般に、自動化された単体テスト(JUnit、Karmaなど)を書くときは、次のことを目指します。

  • すべての境界条件をカバーする
  • 高レベルのカバレッジを取得します。

誰かが言うのを聞いた:

カバレッジと境界条件は単体テストには十分ではありません。コードを変更した場合に破損するように、それらを記述する必要があります。

これは理論的には私にはいいように思えますが、どのように適用すればよいかわかりません。

私の質問は次のとおりですコードが変更されたときに失敗する自動化された単体テストを作成する必要がありますか?変更する場合、どのようにしてください。

6
hawkeye

あなたの目的は、codeが変更されたときに失敗する単体テストではなく、動作が変更されたときに失敗する単体テストを記述することです。ここでの動作とは、質問に対する適切な応答を返す、またはデータベースに適切なものを保存するなど、メソッドの外部呼び出し元が実行することを望んでいることを意味します。 方法それはそれ自体の内部実装であり、その動作ではありません。

実装ではなく動作をテストすることで、コードをリファクタリングして改善を行い、テストを実行してコードの動作を誤って変更していないかどうかを即座に確認できます。

実際には、この目標を完全に達成することは不可能です。メソッドがある場合:

int add(int x, int y) {
    return x + y;
}

必要なだけユニットテストを記述できますが、次のように変更した場合に失敗することはほとんどありません。

int add(int x, int y) {
    if(x==10731 && y == -405571) {
        return 0;
    }
    return x + y;
}

ただし、実用的な範囲で完全な行動範囲に近づくために、いくつかの賢明な手順を実行できます。

  • あなたが言ったように、境界条件とコーナーケースについて考えてください。これらは、偶発的な行動の変化が見られる可能性が最も高い場所です。
  • 行ごとのカバレッジは「必要だが十分ではない」と考えてください。行ごとの完全なカバレッジを取得しながら、可能な限り怠け者になることを想像してみてください。これに続く不適切なテストのセットを書くことがいかに簡単であるかがわかります。
  • メソッドが提供することになっている動作と、それがたどることができる分岐について考えてください。理想的には、その実装を通るすべてのルートについて、期待されるすべての動作を提供することをテストする必要があります。
  • テストのセットを記述したら、「既存のメソッドと同じくらい簡単で、すべてのテストに合格するが、動作が間違っているメソッドの実装はありますか」と質問します。これは、行動範囲が十分かどうかを確認するための良い目安です。

    上記のaddメソッドの例に示されているように、メソッドに変更を加えて、メソッドに余分なものを追加することを完全に防ぐことはできません。しかし、はるかに可能性が高いですが、複雑さを増すことなく、パーツを変更または削除することでバグがこっそり入り込むでしょう(なぜ、複雑さを増すような方法で何かをリファクタリングするのですか?)。したがって、「少なくとも同じくらい単純な」条件を追加することで、実際に達成可能なものを取得できます。

29
Ben Aaronson

与えられた答え-これは間違ったやり方であり、優れたテストのすべての原則に違反している-は正しいです。

しかし、これはプログラミングです。もっとも奇妙なリクエストであっても、常にsomeの合理的な根拠があり、それらを検討することは生産的です。

重要なカーネルコード、またはSSHライブラリの高セキュリティ部分があるとします。これらは、絶対に、いかなる状況下でも、その動作を変更するべきではありません。取るに足らない無限値の小さなサブセットであっても、すべて変更できます。決してテストしないでください。

また、Dev部門が提供するコードに対する単体テストを記述し、ビジネス要件を確実に満たすQA部門が存在するように会社を設立したとします。

この状況では、「重要なコードパスはDevによってのみ変更する必要がありますQAに上層部からのサインオフが通知されている場合」。サインオフと通知のない変更は意図的なものではないため、悪意がある可能性があります。

その場合、イントロスペクションを使用して各メソッドのコンテンツのハッシュを取得し、それを格納されているハッシュと比較するテストは正当なものになる可能性があります。 Method()をシリアライズすることはできませんが、Methodをサブクラス化してシリアライズ可能にすることができます。おそらく、より良いアプローチは、ファイル自体のハッシュを取得することです。または、ファイルをファイルの安全なバックアップと比較します。

ただし、変更が失敗した場合のバージョン管理システムのログを確認して、関連ファイルの変更がダウンロードされたかどうかを確認するのが、おそらく最善の方法です。はいの場合、失敗します。

0
Dewi Morgan