各ユニットテストで答えなければならない5つの質問


原文:
5 Questions Every Unit Test Must Answer
各開発者は、プログラムが本番環境にアップロードされてからエラーが検出されないように、ユニットテストを作成する必要があることを知っています.
ほとんどの開発者は、ユニットテストを作成する基本的な要素を知らない.私はユニットのテストに失敗した回数を計算することができません.調査を経て、開発者がどの機能をテストしようとしているのか、何が問題なのか、なぜ重要なのか全く分からないことに気づきました.
最近のプロジェクトでは、多くのユニットテストをテストユニットに入れましたが、テストの目的は全く説明されていません.私たちは素晴らしいチームを持っているので、警戒心を緩めました.結果は?著者だけが本当に理解できるユニットテストがまだたくさんあります.
幸いなことに、APIを再設計しています.テストユニット全体を再開始します.そうしないと、修復リストの最初の優先順位になります.
これをあなたに起こさせないでください.

テストのルールに影響するものは何ですか?


あなたのテストはソフトウェアの欠陥を防ぐ最初の防御線です.あなたのテストはlintingと静的分析(実際のプログラムロジックの問題ではなく、誤ったサブクラスしか見つからない)よりも重要です.テストは実装自体と同様に重要です.
ユニットテストは多くの機能を組み合わせて、アプリケーションの成功の秘密兵器になります.
  • 設計支援:まずテストを作成することで、理想的なAPI設計をより明確に理解できるようになる
  • 機能文書(開発者向け):実装される機能要件ごとにコードに含まれるテストの説明.
  • 開発者の理解度をテスト:開発者がこの問題をよく理解しているかどうかは、コードのすべての重要な部分の説明からわかります.
  • 品質保証:手動QAはエラーが発生しやすい.私の経験によれば、機能を変更、追加、または削除した後、開発者はテストが必要なすべての機能を覚えることはできません.
  • 継続納入:自動QAは生産環境への導入による破損構築を自動的に防止する機会を提供する.

  • ユニットテストは、これらの広範な目標をすべて満たすために曲解操作を必要としない.逆に、ユニットテストの本質は、これらのすべてのニーズを満たすことです.これらの利点は,丹念に記述され,良好なカバー率を有する試験ユニットの副作用である.

    TDD科学(Test-driven development)


    証拠は
  • TDDでバグの密度を減らすことができる
  • TDDはより多くのモジュール化設計(ソフトウェアの敏捷性/チーム開発速度の向上)を奨励できる
  • TDDはコードの複雑さを低減できる
  • 先書きテスト


    マイクロソフト研究院、IBMとSpringerの研究テストから、テストと後のテストの効果を先に作成し、テスト優先のプロセスが後でテストを追加するよりも良い効果を生むことを常に発見しました.コードを記述する前にテストを記述することを明確にしています.

    良好なユニットテストとは?


    どのようにして良いユニットテストを作成できますか?
    私たちは本当のプロジェクトから非常に簡単な例を見て、この過程を探求します:Stamp Specificationからのcompose()関数.
    十分に明確で簡単なのでtapeを使用してユニットテストを行います.
    作成したユニットテストに答える前に、まずユニットテストの使用方法を理解する必要があります.
  • 設計支援:コード作成前の設計段階で作成
  • 機能文書&テスト開発者の理解度:テストは被験機能の明確な説明を提供すべき
  • 品質保証/継続納入:テストは故障時に納入パイプを停止し、失敗時に良いエラー報告を発生する.

  • ユニットテストをテストレポートとして使用


    テストに失敗した場合、そのテスト失敗レポートは通常、エラーを正確に発見する最初の手がかりであり、根本的な原因を迅速に追跡する秘密は、どこから探しているのかを知ることです.非常に明確なエラーレポートがある場合、このプロセスはより容易になります.

    良いテスト失敗レポートとは

  • 何をテストしていますか?
  • 何をすべきか?
  • 出力は何ですか(実際の動作)?
  • 期待出力は何ですか(期待行動)?

  • 「何をテストしてるの?」スタート

  • コンポーネントのテストは何ですか?
  • この機能は何をすべきか?特定の行動要件をテストしていますか?
  • compose()関数は任意の数の切手(組み合わせ可能な工場関数)を使用して新しい切手を生成する.このテストを作成するには、特定の動作要件をテストする単一のテストの最終目標から後方に作業します.このテストに合格するために、コードはどのような特定の動作を生成する必要がありますか?

    この機能は何をすべきですか?


    私は文字列を書くことから始めるのが好きです.何にも割り当てられていません.関数は入力されませんでした.注目コンポーネントが満たさなければならない特定の要件を明確に記入するだけです.この場合、compose()関数が1つの関数を返すべきであることから始めます.
    簡単な、テスト可能な要件
    'compose() should return a function.'

    今、私たちはいくつかのものをスキップして、残りのテストを充実させます.この文字列は私たちの目標です.事前の陳述は、最終的な結果への関心を維持するのに役立ちます.

    どんなコンポーネントをテストしていますか。


    コンポーネントの各態様の意味は、テストコンポーネントに十分なカバー度を提供するために必要な粒度に応じて、テストによって異なります.
    上記の例では、実行時に「undefined」を投げ出すのではなく、正しいタイプを返すことを確認するために、compose()関数の戻りタイプをテストします.
    この問題をテストコードに変換しましょう.答えはテストの説明に入ります.このステップは、関数呼び出しを行い、テスト実行時にコールバック関数を呼び出すテスト実行器にコールバック関数を渡す場所でもあります.
    test('', assert => {});

    この例では、compose関数の出力をテストします
    test('Compose function output type.', assert => {  
    })

    もちろん、最初の説明も必要です.コールバック関数に入ります.
    test('Compose function output type', assert => {
      'compose() should return a function.'
    })

    出力は何ですか(期待または実際の)?

    equal()私の大好きな断言です.各テストユニットの唯一の可能性のある断言がequal()であれば、世界のほとんどのテストユニットがより良いです.どうして?equal()ということで、テストユニットごとに2つの重要な質問に自然に答えていますが、ほとんどは答えていません.
  • 実際の出力とは?
  • 所望の出力とは?

  • もしあなたがテストを完了したが、この2つの質問に答えなかったら、あなたは本当のユニットテストをしていません.あなたはただいい加減で未熟なテストを持っています.
    もしあなたがこの文章から一つのことしか見えなかったら、それはEqualあなたの新しいデフォルトの断言です.これは各優秀なテストユニットの主要な構成部分です.数百種類の派手な断言を持つすべての断言ライブラリがあなたのテストの品質を破壊しています.

    一つの挑戦


    ユニットテストを作成するときにもっと良いことを望んでいますか?来週は、equalまたはdeepEqualを使って、それぞれのアサーションを作成してみるか、あなたのアサーションライブラリではあまり選択肢がありません.その品質がユニットテストに影響を与える心配はありません.私の収入はあなたにこのような訓練があなたのユニットテストを著しく向上させることを教えます.
    次のコードは何に見えますか?
    const actual = '';
    const expected = '';

    最初の問題は確かにテストの失敗で二重の責任を負うことです.この質問に答えることで、あなたのコードも別の質問に答えることができます.
    const actual = '';

    注意すべき重要な点は、actual値がコンポーネント共通APIを使用するときに生成されなければならないことです.そうでなければ、テストは意味がありません.
    例に戻ります.
    const actual = typeof compose();
    const expected = 'function';
    actualおよびexpectedという変数に特別に値を付けるのではなく、断言を構築することができますが、私は最近、各テストで変数actualおよびexpectedに値を付け始め、私のテストを読みやすくしていることに気づきました.
    これを見て、どのようにしてこの断言をはっきりさせたのですか.
    assert.equal(actual, expected, 
      'compose() should returns a function';
    )

    テストコードでhowとwhatを分離しました
  • how:どうやってこの値を得たのですか?変数の割り当てを見てください.
  • what:つまり何をテストしているのですか?断言の説明を見てみましょう.

  • テストの結果を読むのは、高品質のバグレポートを読むのと同じです.
    コンテキスト内のすべての内容を見てみましょう.
    import test from 'tape';
    import compose from '../source/compose';
    
    test('Compose function output type', assert => {
      const actual = typeof compose();
      const expected = 'function';
    
      assert.equal(actual, expected, 'compose() should return a function');
    
      assert.end();
    })

    次に、テストコードを作成し、次の質問に答えてください.
  • 何をテストしていますか?
  • 何をすべきか?
  • 実際の出力は何ですか?
  • 所望の出力は何ですか?
  • テストの再生方法

  • 最後の質問は、導出用actualコード回答に値します.

    ユニットテストテンプレート

    import test from 'tape';
    
    // For each unit test your write,
    // answser these questions
    
    test('What component aspect are you testing?', assert => {
      const actual = 'What is the actual output?';
      const expected = 'What is the expected output?';
    
      assert.equal(actual, expected, 
      'what should the feature do?');
    
      assert.end();
    });

    ユニットテストの使用例はたくさんありますが、良いテストをどのように書くかはまだ長い道のりがあります.