テスト用にプライベートなものを内部/公開にするか、PrivateObjectのようなハックを使用しますか?


26

私はコードテストの初心者であり、assert以前は売春婦でした。ユニットテストで私を心配していることの1つは、そうでなければそうであったpublic(または少なくともinternal)フィールドを作成し、それらprivateを解除readonlyし、代わりにprivateメソッドprotected virtualを作成するなどが必要になることが多いということです...

私は最近、PrivateObjectクラスのようなものを使用して、リフレクションを介してオブジェクト内のすべてにアクセスすることで、これを回避できることを発見しました。しかし、これにより、テストの保守性が低下します(コンパイル時ではなく実行時に失敗します。単純な名前変更によって破損し、デバッグが難しくなります...)。これについてのあなたの意見は何ですか?アクセス制限に関する単体テストのベストプラクティスは何ですか?

編集:たとえば、ディスク上のファイルにキャッシュを持つクラスがあり、テストでは代わりにメモリに書き込むことを検討してください。


2
pythonの人々は公開されています。彼らは幸せです。なぜ心配なの?すべてを公開しないのはなぜですか?
S.Lott

12
これは、大半の主要言語のベストプラクティスとはかけ離れているためです。本当の答えは、優れたインターフェイスなどを使用して、モックオブジェクトを使用してテストを実行できるようにすることです。
リグ

2
@Rig:Pythonはトップ言語ではありませんか?面白い。
S.Lott

7
「大半のトップ言語のベストプラクティスからは程遠い」というのは、「Pythonはトップ言語ではない」という論理的な意味ではありません。
マイクナキス

1
正確には、それはトップ言語ですが、ほとんどのトップ言語はPythonではなく、適切なスコープを設定することを推奨しています。私は声明を支持します。変数がスコープを維持することを保証しながら、高度にテスト可能なソフトウェアを作成するように設計されたパターンがあります。Pythonプログラマーでさえ、私が見たものの接頭辞でスコープをエミュレートする傾向があります。
リグ

回答:


36

あなたは決してする必要はありません

メイクpublic(あるいは少なくともinternal)であったであろうフィールドprivate未し、そうでない場合はreadonly、それらを、メイクprivate方法protected virtualの代わりに

特に、フィールドを読み取り専用にしないと、不変オブジェクトが変更可能になり、それは災害になります。

テストでは、オブジェクトをブラックボックスWikipedia)と見なす必要があります。つまり、実装の詳細ではなく、オブジェクトのパブリックインターフェイスのみに関係する必要があります。

パブリックインターフェイスを使用してオブジェクトを十分にテストできない場合は、テストを容易にする正式で便利な拡張機能をインターフェイスに提供する方法を見つける必要があります。たとえば、Register / Deregisterメソッドのペアのみを含む登録システムは、手元のアプリケーションに必要ではない場合でも、おそらくIsRegisteredメソッドの恩恵を受けるでしょう。それでも、これはインターフェースに対する正式で有用な拡張機能であり、偶然にもテストに対応します。

重要なことは、オブジェクトの実装を変更しても、単体テストを変更する必要がないことです。理論的には、単体テストを一度書くことができ、単体テストで動作するようにテスト対象オブジェクトの複数の完全に異なる実装をコーディングするように複数のプログラマーに依頼する必要があります。


2
まさに!リフレクションやハックなしで単体テストを実行できない場合は、おそらくAPIまたは設計に間違いがあります。
ファルコン

テストでのモックを支援するprivateメソッドprotected virtualを作成することは悪い練習と見なされると言っていますか?
ロブラ

1
@Robula私の本では、はい。私は非公開メンバーにアクセスできるために何の役にも立たないので、本番コードと同じパッケージにテストを書くことさえしません。モックも使いません。もちろん、モックを使用する必要がある場合は、モックを容易にするために必要なことをすべて実行する必要があるため、多くの場合、保護された仮想は実用的な妥協となる可能性があります。しかし理想的には、デザインはモックを必要とせず、代替実装のみを必要とし、理想的にはテストはホワイトボックステストではなくブラックボックステストであるため、モックなしで統合でテストされます。
マイクナキス

13

C#では、InternalsVisibleToAttributeを使用して、テストアセンブリがテストするアセンブリinternal内のクラスを表示できるようにします。あなたはすでにこれを知っているようです。

ほとんどの場合、アセンブリのパブリックAPIのテストにのみ興味があります。あるユニットのホワイトボックステストを行いたい場合は、コードをinternalクラスに移動し、publicそのクラスのメソッドにします。次に、そのクラスの単体テストをコーディングできます。

これは、依存性注入と戦略パターンに適しています。メソッドをインターフェイスに抽象化し、インターフェイスを親オブジェクトのコンストラクタに挿入し、親が適切に委任することをテストするだけです。次に、子オブジェクトが適切に動作することをテストできます。これにより、すべてがよりモジュール化されます。


8

私の経験では、テストのためにクラスの内部を特別に公開しないことが最善です。これにより、テストを記述しやすくなるように見えますが。テストはクラスの最初のクライアントです。そのため、パブリックインターフェイスを介してクラスをテストすることが難しい場合、おそらく他の場所でもクラスを使用することは困難です。

クラスがパブリックAPIを介してテストするのがどれほど簡単かは、クラスがどれほど簡単に使用できるかについてのフィードバックです。テストの一部は、クラスの使用法をプロトタイプ化する方法と考えてください。

テストがパブリックAPIを介して利用できないクラスについて何かを感知する必要がある理由を考えてみてください。おそらくあなたのクラスはやりすぎで、代わりに協力するクラスのグループに分解する必要がありますか?その後、連携するクラスの一部をモックして、テスト対象のクラスが何をしているかを感知できます。

依存関係の反転のプリンシパルを適用し、テストでモックできるクラス間にインターフェースを導入してください。制御の反転を使用して、共同作業者をテストに提供できます。

また、適切な情報が公開され、残りの情報が非表示になる、堅牢で疎結合の方法でクラスインターフェイスを構築するために、"tell do n't ask"プリンシパルを適用することを検討してください。


6

個人的には、テストしているコードをできるだけ純粋なままにしておき、テストコードにハッキングが必要な場合(およびC ++の厄介なポインターなど)、それを喜んで行います。



1
同意する、これはそれを行う方法です。テストコードのさを保ち、何も傷つけないようにします。
アランデリモン

@AlanDelimonそれはその後の保守プログラマーの心を傷つけないかもしれませんか?
フラミンペンギン

1
@flamingpenguinのいコードは、プログラマをどこでも傷つける可能性があります。しかし、いテストコードは、クラスを変更する人にのみ影響し、単純にそれを消費する人にも影響しないため、害が少ない可能性があります。
ダン・ニーリー

2
@flamingpenguin可能性はありますが、codeいコードをどこかに配置する必要がある場合は、単体テストで修正する必要が少なく、アプリケーションの一部になる可能性があります。
アランデリモン

5

コードの可視性は、単体テストとは関係ありません!

メソッドをテストから隠す目的ではなく、メソッドをプライベートにし、テスト用に公開するためにそれらを公開しませんか?これは、テストではなく、ここで不可欠な実装です。コードの証明としてのサーバーですが、コードではありません

隠された(プライベートまたは内部の)メソッドおよびプロパティへのアクセスを有効にする方法はたくさんあります。多くのテストフレームワークとIDE(Visual Studioなど)は、アクセスに必要なすべてを生成することでここでサポートします。テストケースを作成するだけです。それでは、なぜ心配するのですか?コードをきれいに整頓してください。

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