web-dev-qa-db-ja.com

プライベートメソッドをユニットテストする必要を回避する方法

私はあなたがプライベートメソッドをテストすることになっていないことを知っています、そしてそれが必要であるように見えるなら、そこに出てくるのを待っているクラスがあるかもしれません。

しかし、私はそれらのパブリックインターフェイスをテストできるようにするためだけに膨大なクラスを持ちたくありません。多くのクラスでは、パブリックメソッドをテストするだけの場合、多くの依存関係をモックしなければならず、ユニットテストは巨大で従うのは難しい。

私は、パブリックメソッドをテストするときにプライベートメソッドをモックし、プライベートメソッドをテストするときに外部依存関係をモックすることを好みます。

私は狂っていますか?

15
Fran Sevillano

あなたは部分的に正しい-あなたはすべきではない直接プライベートメソッドをテストする。クラスのプライベートメソッドは、1つ以上のパブリックメソッドによって呼び出される必要があります(おそらく間接的に-パブリックメソッドによって呼び出されるプライベートメソッドが他のプライベートメソッドを呼び出す可能性があります)。したがって、パブリックメソッドをテストするときは、プライベートメソッドもテストします。テストされていないプライベートメソッドがある場合、テストケースが不十分であるか、プライベートメソッドが使用されていないため削除できます。

ホワイトボックステストアプローチを採用している場合は、パブリックメソッドを中心にユニットテストを構築するときに、プライベートメソッドの実装の詳細を検討する必要があります。ブラックボックスアプローチを採用している場合は、パブリックメソッドまたはプライベートメソッドの実装の詳細に対してテストするのではなく、予想される動作に対してテストする必要があります。

個人的に、私はユニットテストに対してホワイトボックスアプローチを好みます。私は、テスト対象のメソッドとクラスをさまざまな状態にして、パブリックメソッドとプライベートメソッドで興味深い動作を引き起こすテストを作成し、その結果が期待どおりであることを主張できます。

だから-あなたのプライベートメソッドをあざけらないでください。それらを使用して、提供する機能を適切にカバーするために何をテストする必要があるかを理解してください。これは特にユニットテストレベルで当てはまります。

24
Thomas Owens

これは非常に悪い考えだと思います。

プライベートメンバーの単体テストを作成する際の問題は、製品のライフサイクルとの適合性が低いことです。

これらのメソッドをプライベートにするように選択した理由は、それらのメソッドがクラスが実行しようとしていることの中心ではなく、現在その機能を実装する方法のヘルパーにすぎないためです。リファクタリングすると、これらのプライベートな詳細は変更される可能性が高く、リファクタリングとの間に摩擦が発生します。

また、パブリックメンバーとプライベートメンバーの主な違いは、パブリックAPIを慎重に検討し、それを適切に文書化し、よく確認することです(アサーションなど)。しかし、プライベートAPIを使用する場合、慎重に考えることは無意味です(その使用は非常にローカライズされているため、無駄な作業です)。プライベートメソッドを単体テストに入れると、それらのメソッドに外部依存関係を作成することになります。つまり、APIは安定していて、十分に文書化されている必要があります(その場合、ユニットテストが失敗した場合と失敗した理由を誰かが理解する必要があるためです)。

私はあなたに提案します:

  • それらのメソッドがプライベートであるべきかどうかを再考する
  • ワンタイムテストを作成します(今すぐ正しいことを確認し、一時的に公開してテストできるようにしてから、テストを削除します)。
  • #ifdefおよびアサーションを使用して、条件付きテストを実装に組み込みました(テストはデバッグビルドでのみ行われます)。

この機能をテストする傾向と、現在のパブリックAPIでテストするのが難しいことを感謝します。しかし、個人的には、テストカバレッジよりもモジュール性を重視しています。

4
Lewis Pringle

UnitTestsは、コードではなくパブリック監視可能動作をテストします。「パブリック」は、戻り値と依存関係との通信を意味します。

「ユニット」は、同じ問題を解決する任意のコードです(より正確には、変更する理由が同じです)。それは単一のメソッドまたはクラスの束かもしれません。

テストしたくない主な理由private methods is:それらは実装の詳細であり、refactoringの間にそれらを変更することができます(機能を変更せずにOO原則を適用することによってコードを改善します)。これは、ユニットテストを変更したくない場合であり、リファクタリング中にCuTのbehaviorが変更されないことを保証できます。

しかし、私はそれらのパブリックインターフェイスをテストできるようにするためだけに膨大なクラスを持ちたくありません。パブリックメソッドをテストするだけの場合、多くの依存関係をモックしなければならず、ユニットテストは巨大で従うのは難しい。

私は通常、逆のことを経験します。クラスが小さいほど(クラスの責任が少ないほど)、依存関係が少なくなり、書き込みと読み取りの両方の単体テストが容易になります。

理想的には、クラスに同じ抽象レベルパターンを適用します。これは、クラスがいくつかのビジネスロジックを提供することを意味します(独自の状態を維持せずに、パラメーターでのみ機能する「純粋な関数」が望ましい)(x)or同時にではなく、他のオブジェクトのメソッドを呼び出す。

このように、ビジネス動作をユニットテストすることは簡単であり、「委任」オブジェクトは通常失敗するのは簡単すぎる(分岐なし、状態変更なし)なので、ユニットテストは不要であり、テストをそのままにしておくことができます。 integrationまたはmodule tests

3
Timothy Truckle

ユニットテストは、コードを扱う唯一のプログラマである場合、特にアプリケーションが非常に大きいか非常に複雑な場合に、ある程度の価値があります。ユニットテストが不可欠になるのは、同じコードベースで作業するプログラマの数が多い場合です。ユニットテストの概念は、これらの大規模なチームで作業する際のいくつかの困難に対処するために導入されました。

単体テストが大規模なチームに役立つ理由は、すべて契約についてです。私のコードが他の誰かによって書かれたコードを呼び出す場合、私はさまざまな状況で他の人のコードが何をするのかを想定しています。これらの仮定が依然として当てはまる場合、コードは引き続き機能しますが、どの仮定が有効であるかをどのようにして知ることができ、それらの仮定がいつ変更されたかをどのように知ることができますか?

これがユニットテストの出番です。クラスの作成者は、クラスの予想される動作を文書化するユニットテストを作成します。単体テストは、クラスを使用するすべての有効な方法を定義し、単体テストを実行すると、これらのユースケースが期待どおりに機能することが検証されます。クラスを利用したい別のプログラマーは、ユニットテストを読んでクラスに期待できる動作を理解し、これをクラスの動作に関する仮定の基礎として使用できます。

このようにして、クラスのパブリックメソッドシグネチャとユニットテストは、クラスの作成者と、コードでこのクラスを利用する他のプログラマーとの間の契約を形成します。

このシナリオで、プライベートメソッドのテストを含めるとどうなりますか?明らかにそれは意味がありません。

あなたがあなたのコードに取り組んでいる唯一のプログラマーであり、あなたがコードをデバッグする方法としてユニットテストを使いたいなら、私はそれで何の害も見ません、それは単なるツールであり、あなたはそれがうまくいく方法でそれを使うことができますあなたが、それはユニットテストが導入された理由ではなく、ユニットテストの主な利点を提供していません。

1
bikeman868

このような質問に答える前に、実際に達成したいことを決定する必要があります。

あなたはコードを書きます。あなたはそれがその契約を果たすことを望みます(言い換えれば、それはそれが行うことになっていることを行います。それが何をすべきかを書き留めることは、一部の人々にとって大きな前進です)。

コードが想定どおりの動作をすることを合理的に確信するには、コードを十分にじっと見つめるか、「コードがこれらすべてのテストに合格した場合は正しい」と納得させるのに十分なケースをテストするテストコードを記述します。

多くの場合、あなたはいくつかのコードの公に定義されたインターフェースにのみ興味があります。私があなたのライブラリを使用する場合、私はあなたがどのようにそれを正しく動作させたかは気にしません、それがdoesが正しく動作することだけです。単体テストを実行して、ライブラリが正しいことを確認します。

しかし、あなたはライブラリを作成しています。正しく機能させるのは難しい場合があります。ライブラリが操作Xを正しく実行することだけを気にしているとしましょう。Xの単体テストがあります。ライブラリを作成する開発者であるあなたは、ステップA、B、Cを組み合わせてXを実装します。ライブラリを機能させるには、A、B、Cがそれぞれ正しく機能することを確認するテストを追加します。これらのテストが必要です。 「プライベートメソッドの単体テストを行うべきではない」と言ってもまったく意味がありません。 あなたこれらのプライベートメソッドのテストが必要です。 たぶんプライベートメソッドのユニットテストが間違っていると誰かが言った。しかし、それは、それらを「単体テスト」ではなく「プライベートテスト」など、好きな名前で呼ぶことを意味するだけです。

Swift言語は、A、B、Cをパブリックメソッドとして公開したくないという問題を解決します。これは、関数に「テスト可能な」属性を与えることによってテストしたいという理由だけです。コンパイラは単体テストから呼び出されるが、非テストコードからは呼び出されないプライベートテスト可能なメソッド。

1
gnasher729

実用的です。インスタンスの状態とパブリックメソッドへのパラメーターを設定して、それらのケースがそこで発生するようにして、プライベートメソッドで特殊なケースをテストすることは、非常に複雑になることがよくあります。

これらの「プライベート」メソッドをテストするために、internalアクセサー(フラグInternalsVisibleToテストアセンブリと共に)を追加し、DoSomethingForTesting(parameters)という明確な名前を付けます。

もちろん、実装はいつか変更される可能性があり、テストアクセサーを含むこれらのテストは廃止されます。これは、テストされていないケースや判読できないテストよりも優れています。

0
Bernhard Hiller

はい、あなたは狂っています... FOXのように!

プライベートメソッドをテストする方法は2つあり、そのいくつかは言語に依存しています。

  • 反射!ルールを破る!
  • それらを保護し、継承し、オーバーライドする
  • friend/InternalsVisibleToクラス

概して、プライベートメソッドをテストする場合は、依存関係のパブリックメソッドに移動し、テスト/注入する必要があります。

0
Ewan