視点:
それでは、一歩後退して、TDDが私たちを助けようとしているものを尋ねましょう。TDDは、コードが正しいかどうかを判断するのに役立ちます。正確には、「コードはビジネス要件を満たしていますか?」という意味です。セールスポイントは、将来的に変更が必要になることがわかっていることであり、変更を行った後もコードが正しいままであることを確認したいということです。
細部に迷い、私たちが達成しようとしているものを見失ってしまうのは簡単だと思うからです。
原則-SAP:
私はTDDの専門家ではありませんが、シングルアサーションプリンシパル(SAP)が教えようとしているものの一部が欠けていると思います。SAPは、「一度に1つのことをテストする」と言い換えることができます。しかし、TOTATはSAPほど簡単に舌から外れません。
一度に1つのことをテストするということは、1つのケースに集中することを意味します。1つのパス。1つの境界条件。1つのエラーケース。1 どんなテストあたり。そして、その背後にある原動力となるアイデアは、テストケースが失敗したときに何が壊れたかを知る必要があるため、問題をより迅速に解決できることです。1つのテスト内で複数の条件(つまり、複数の条件)をテストし、テストが失敗した場合は、さらに多くの作業が必要になります。最初に、複数のケースのどれが失敗したかを特定し、次にそのケースが失敗した理由を把握する必要があります。
一度に1つのことをテストすると、検索範囲がはるかに小さくなり、欠陥がより迅速に特定されます。「一度に1つのことをテストする」とは、必ずしも一度に複数のプロセス出力を見ることを除外するわけではないことに注意してください。たとえば、「既知の良好なパス」をテストするとき、特定の結果値foo
と別の値が表示されるbar
と予想される場合がfoo != bar
あり、テストの一部としてそれを確認する場合があります。重要なのは、テスト対象のケースに基づいて出力チェックを論理的にグループ化することです。
原則-PMP:
同様に、Private Method Principle(PMP)が私たちに教えなければならないことについて、あなたは少し欠けていると思います。PMPは、システムをブラックボックスのように扱うことを推奨しています。特定の入力に対して、特定の出力を取得する必要があります。ブラックボックスがどのように出力を生成するかは気にしません。出力が入力と一致することだけが重要です。
PMPは、コードのAPIの側面を見るための非常に優れた視点です。また、テストする必要があるものの範囲を決めるのに役立ちます。インターフェイスポイントを特定し、それらが契約の条件を満たしていることを確認します。インターフェイスの背後にある(プライベート)メソッドがどのように機能するかを気にする必要はありません。あなたは彼らが彼らがすることになっていたことをしたことを確認する必要があります。
応用TDD(あなたのために)
したがって、あなたの状況は、通常のアプリケーションを超えて少ししわを示します。アプリのメソッドはステートフルであるため、出力は入力だけでなく、以前に行われたことにも左右されます。私は<insert some lecture>
ここで状態が恐ろしく、何とか何とかであるべきだと確信していますが、それは本当にあなたの問題を解決するのに役立ちません。
さまざまな潜在的な状態と、遷移をトリガーするために何をする必要があるかを示す何らかの状態図表があると仮定します。そうでない場合は、このシステムのビジネス要件を表現するのに役立つため、必要になります。
テスト:最初に、状態の変化を実現する一連のテストを実行します。理想的には、発生する可能性のあるすべての状態変化をテストするテストがありますが、その範囲全体を実行する必要のないいくつかのシナリオを見ることができます。
次に、データ処理を検証するテストを作成する必要があります。これらの状態テストの一部は、データ処理テストを作成するときに再利用されます。たとえば、とにFoo()
基づいて異なる出力を持つメソッドがあるInit
としState1
ます。" in "のChangeFooToState1
場合に出力をテストするために、セットアップステップとしてテストを使用する必要があります。Foo()
State1
私が言及したいそのアプローチの背後にある含意があります。 ネタバレ、これは私が純粋主義者を激怒させる場所です
まず、ある状況ではテストとして、別の状況ではセットアップとして何かを使用することを受け入れる必要があります。一方で、これはSAPの直接的な違反のようです。しかし、論理的にChangeFooToState1
2つの目的を持っていると考えると、SAPが教えている精神を満たしていることになります。Foo()
状態の変更を確認する必要がある場合ChangeFooToState1
は、テストとして使用します。また、「Foo()
」の「」の出力を検証する必要がある場合は、セットアップとしてState1
使用ChangeFooToState1
しています。
2番目の項目は、実用的な観点からは、システムの完全にランダム化された単体テストを望まないということです。出力検証テストを実行する前に、すべての状態変更テストを実行する必要があります。SAPは、この注文の背後にある指針の一種です。明らかなことを述べるために-テストとして失敗した場合、セットアップとして何かを使用することはできません。
それを一緒に入れて:
状態図を使用して、遷移をカバーするテストを生成します。再び、ダイアグラムを使用して、状態によって駆動されるすべての入力/出力データ処理ケースをカバーするテストを生成します。
そのアプローチに従えば、bloated, complicated, long, and difficult to write
テストの管理が少し簡単になるはずです。一般に、それらは最終的には小さくなり、より簡潔になります(つまり、より複雑ではなくなります)。テストはより分離されているか、モジュール化されていることにも注意してください。
さて、良いテストを書くのは少し手間がかかるので、このプロセスが完全に痛みを伴わないと言うつもりはありません。また、いくつかのケースでは2番目のパラメーター(状態)をマッピングしているため、それらのいくつかは依然として困難です。余談ですが、なぜステートレスシステムの方がテストの構築が簡単なのか、もう少しはっきりしているはずです。しかし、このアプローチをアプリケーションに適応させると、アプリケーションが正しく機能していることを証明できることに気付くはずです。