19

c++ の pImpl イディオムは、クラスのユーザーからクラスの実装の詳細 (= プライベート メンバー) を隠すことを目的としています。ただし、テストの観点から通常は悪いと見なされる、そのクラスの依存関係の一部も隠します。

たとえば、クラス A が、A.cpp からのみアクセスできるクラス AImpl にその実装の詳細を隠し、AImpl が他の多くのクラスに依存している場合、テスト フレームワークがクラ​​ス A のメソッドにアクセスできないため、クラス A の単体テストが非常に困難になります。 AImpl に依存関係を注入する方法もありません。

誰もこの問題に遭遇したことがありますか? 解決策を見つけましたか?

- 編集 -

関連するトピックでは、内部ではなく、インターフェイスによって公開されたパブリック メソッドのみをテストする必要があると人々が提案しているようです。そのステートメントを概念的に理解することはできますが、プライベート メソッドを個別にテストする必要があることがよくあります。たとえば、パブリック メソッドが重要なロジックを含むプライベート ヘルパー メソッドを呼び出す場合などです。

4

5 に答える 5

17

pimpl の背後にある考え方は、実装の詳細をクラスから隠すことではなく (プライベート メンバーは既にそれを行っています)、実装の詳細をヘッダーから移動することです。問題は、C++ のインクルード モデルでは、プライベート メソッド/変数を変更すると、このファイルを含むすべてのファイルが強制的に再コンパイルされることです。それは苦痛であり、それが吹き出物が排除しようとする理由です. 外部ライブラリへの依存を防ぐのには役立ちません。他のテクニックはそれを行います。

単体テストは、クラスの実装に依存するべきではありません。彼らは、クラスが実際に本来の動作をすることを確認する必要があります。本当に重要なのは、オブジェクトが外の世界とどのように相互作用するかだけです。テストで検出できない動作は、オブジェクトの内部にある必要があり、無関係である必要があります。

そうは言っても、クラスの内部実装が複雑すぎる場合は、そのロジックを別のオブジェクトまたは関数に分割することをお勧めします。基本的に、内部動作が複雑すぎて間接的にテストできない場合は、それを別のオブジェクトの外部動作にしてテストします。

たとえば、文字列をコンストラクターのパラメーターとして受け取るクラスがあるとします。文字列は、オブジェクトの動作の一部を指定する実際の小さなミニ言語です。(文字列はおそらく構成ファイルか何かから来ています)。理論的には、さまざまなオブジェクトを作成して動作をチェックすることで、その文字列の解析をテストできるはずです。しかし、ミニ言語が十分に複雑な場合、これは難しくなります。そこで、文字列を受け取り、コンテキストの表現 (連想配列など) を返す別の関数を定義します。次に、メイン オブジェクトとは別にその解析関数をテストできます。

于 2010-05-07T00:40:46.837 に答える
17

単体テストで A の実装の内部にアクセスする必要があるのはなぜですか?

単体テストは A をテストする必要があるため、A の入力と出力のみを直接処理する必要があります。何かが A のインターフェイスで (直接的または間接的に) 見えない場合、実際には Aimpl の一部である必要はまったくないかもしれません (その結果は外部の世界から見えないため)。

Aimpl がテストする必要のある副作用を生成する場合、それは設計を検討する必要があることを示しています。

于 2010-05-06T23:38:12.093 に答える
11

依存性注入を正しく行っている場合、依存性クラス A はそのパブリック インターフェイスを介して渡される必要があります。依存性が原因で pImpl がテストに干渉している場合、それらの依存性を注入していないように見えます。

単体テストは、クラス A が公開しているパブリック インターフェイスにのみ関係する必要があります。依存関係でA が内部的に行うことは、あなたの関心事ではありません。すべてが適切に注入されている限り、A の内部実装について心配する必要なく、モックを渡すことができるはずです。ある意味では、テスト可能性と適切な pImpl は密接に関連していると言えます。テスト不可能な実装は、隠してはならない詳細を隠しているからです。

于 2010-05-06T23:43:22.713 に答える
0

単体テストでは、実装クラスをそのペースでテストする必要があります。PIMPL クラスが表示されると、既に「統合」の領域に入っているため、U/T はそのようには適用されません。PIMPL は、実装を隠すことがすべてです。実装のクラス設定を知っている必要はありません。

于 2015-02-03T21:34:53.887 に答える