単体テスト-はじめに


14

ユニットテストを始めたばかりですが、そのすべてのポイントを本当に理解しているかどうかはわかりません。チュートリアルと本をすべて読んでいますが、2つの簡単な質問があります。

  1. ユニットテストの目的は、実際に書いたコードをテストすることだと思いました。ただし、テストを実行できるようにするには、元のコードを変更する必要があるようです。この時点では、実際に作成したコードではなく、テスト用に作成したコードをテストしています。

  2. ほとんどのコードは外部ソースに依存しています。ただし、コードをリファクタリングすると、元のコードが破損したとしても、外部ソースはテストケース内の単なるマックアップであるため、テストは正常に実行されます。単体テストの目的に反しませんか?

ここで口がきけない場合は申し訳ありませんが、誰かが私を少し啓発できると思いました。

前もって感謝します。

回答:


7

私の0.02 $ ...これは少し主観的ですので、一粒の塩を取りますが、うまくいけば、あなたが考えたりダイアログを起動したりできるようになります:

  1. 私にとっての単体テストの主な目的は、あなたが書いたコードが、あなたのコードが満たそうとしている契約とエッジケースを確実に満たすことです。ユニットテストを実施することで、適切な状態カバレッジがある場合、コードをリファクタリングするときに(または将来誰か他の人が)コードの外部コンシューマーに影響を与えないようにすることができます。(少なくとも、それらが影響を受けないようにするつもりであれば)。

    ほとんどの場合、実稼働環境に出荷でき、簡単に単体テストできるコードを作成できるはずです。開始するのに適した場所は、依存性注入のパターンとフレームワークを調べることです。(またはあなたの言語/選択したプラットフォームのための他の哲学)。

  2. 外部実装がコードに影響を与える可能性があることは正しいです。ただし、大規模システムの一部としてコードが正しく機能することを確認することは、統合テストの機能です。(さまざまな労力で自動化することもできます)。

    理想的には、コードはサードパーティコンポーネントのAPIコントラクトのみに依存する必要があります。つまり、モックが正しいAPIを満たしている限り、ユニットテストは依然として価値を提供します。

    それは、統合テストだけを優先して単体テストを行うことをやめたときがあったことをすぐに認めますが、それは私のドキュメントが不十分に文書化されたAPIを持つサードパーティのコンポーネントと非常にやりとりしなければならなかった場合だけです。(つまり、ルールではなく例外)。


5
  1. 最初にテストを書いてみてください。そうすれば、コードの振る舞いの強固な基盤が得られ、テストはコードの必要な振る舞いの契約になります。したがって、テストに合格するようにコードを変更すると、「テストに合格するようにコードを変更する」のではなく、「テストで提案された契約を満たすようにコードを変更する」ことになります。
  2. さて、スタブとモックの違いに注意してください。コードの変更による影響を受けないことは、スタブの特徴的な動作ですが、モックではありません。モックの定義から始めましょう:

    Mockオブジェクトは、テスト条件下で実際のオブジェクトを置き換え、システムまたはユニットテストの一部としてそれ自体に対する呼び出し(相互作用)を検証できます。

    -単体テストの技術

基本的に、モックはインタラクションに必要な動作を確認する必要があります。したがって、リファクタリング後にデータベースとの対話が失敗した場合、モックを使用したテストも失敗するはずです。もちろんこれには制限がありますが、慎重に計画すれば、モックは「そこに座っている」だけでなく、「単体テストの目的を損なう」ことはありません。


1

良い質問をすることは決して愚かではありません。

ご質問にお答えします。

  1. ユニットテストの目的は、すでに書いたコードをテストすることではありません。時間の概念はありません。TDDでのみ、最初にテストすることになっていますが、どのようなユニットテストにも厳密には適用されません。ポイントは、クラスレベルでプログラムを自動的かつ効率的にテストできることです。コードを変更することを意味する場合でも、そこに到達するために必要なことを行います。そして、秘密を教えてください-それはしばしばそれを意味します。
  2. テストを書くとき、テストが正しいことを確認するのに役立つ2つの主要なオプションがあります。

    • 各テストの入力を変更する
    • その後、あなたのプログラムが正常に動作することを保証し、そしてあなたのプログラムが確実に対応するテストケースの書き込みというテストケースを書くしません、それはいけないように動作します

    以下に例を示します。

    TEST(MyTest, TwoPlusTwoIsFour) {
        ASSERT_EQ(4, 2+2);
    }
    
    TEST(MyTest, TwoPlusThreeIsntFour) {
        ASSERT_NE(4, 2+3);
    }
    

    その上コード(サードパーティライブラリではなく)内のロジックを単体テストしている場合、そのコンテキスト内で他のコードの破損を心配しないことはまったく問題ありません。基本的に、ロジックがラップしてサードパーティのユーティリティを使用する方法をテストしています。これは、古典的なテストシナリオです。

クラスレベルでのテストが完了したら、クラス(私が理解しているものからの仲介者)とサードパーティのライブラリとの統合のテストに進むことができます。これらのテストは統合テストと呼ばれ、モックではなく、すべてのクラスの具体的な実装を使用します。彼らは少し遅いですが、それでも非常に重要です!


1

void main()データベースアクセスから出力生成まで、すべてを実行するモノリシックアプリがあるようです。適切な単体テストを開始する前に、ここにいくつかの手順があります。

1)複数回記述/コピーペーストされたコードを見つけます。たとえそれがただであってもstring fullName = firstName + " " + lastName。次のようなメソッドに分割します。

private static string GetFullName (firstName, lastName)
{
    return firstName + " " + lastName;
}

これで、単体テスト可能なコードができましたが、些細なことかもしれません。単体テストを作成します。このプロセスをすすぎ、繰り返します。最終的には論理的にグループ化されたメソッドが大量に発生し、そこから多くのクラスを抽出できます。これらのクラスのほとんどはテスト可能です。

おまけとして、複数のクラスを抽出したら、それらからインターフェースを抽出し、オブジェクト自体ではなくインターフェースと通信するようにプログラムを更新できます。その時点で、プログラムをまったく変更せずに、モック/スタブフレームワーク(または、手巻きの偽物)を使用できます。これは、データベースクエリをクラス(または多数)に抽出すると非常に便利になります。これは、クエリ返すデータを偽造できるようになったためです。


0

ある賢い人は、「テストするのが難しいなら、おそらく悪いコードだ」と言った。それが、コードを書き直し、それをユニットテストできるようにすることは悪いことではない理由です。外部依存関係のあるコードはテストするのが非常に難しく、コードのリスクを表します。可能な限り回避し、コードの特定の統合領域fxに集中する必要があります。ファサード/ゲートウェイタイプクラス。これにより、外部コンポーネントの変更に対処しやすくなります。

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