JUnit は、私のクラスで公開されているメソッドのみをテストします。非公開 (つまり、非公開、保護) で junit テストを行うにはどうすればよいですか?
junit を使わなくてもテストできるのですが、junit の標準的な方法は何なのか気になりました。
JUnit は、私のクラスで公開されているメソッドのみをテストします。非公開 (つまり、非公開、保護) で junit テストを行うにはどうすればよいですか?
junit を使わなくてもテストできるのですが、junit の標準的な方法は何なのか気になりました。
単体テストに関する 1 つの考え方では、パブリック API のみを単体テストする必要があるため、パブリック メソッドのみをテストできるようにする必要があり、そうすることで、非パブリック メソッドのコードをカバーする必要があるとされています。あなたのマイレージは異なる場合があります; これは、ある場合もあるし、そうでない場合もあると思います。
そうは言っても、非公開メソッドをテストするにはいくつかの方法があります。
お役に立てれば。
多くの単体テストの問題と同様に、private メソッドのテストは、実際には偽装された設計上の問題です。プライベート メソッドをテストするためにトリッキーなことをしようとするのではなく、プライベート メソッドのテストを書きたいと思ったときは、「パブリック メソッドで徹底的にテストできるようにするには、これをどのように設計する必要があるか」と自問します。
それがうまくいかない場合、JUnitX ではプライベート メソッドをテストできますが、JUnit 3.8 でしか利用できないと思います。
JUnit テストを作成するときは、微妙なマインド シフトを行う必要があります。「私は今、自分のクラスのクライアントです」。つまり、private は private であり、クライアントに表示される動作のみをテストします。
メソッドを本当に非公開にする必要がある場合は、テストのためだけにメソッドを表示するのは設計上の欠陥だと思います。クライアントが見ているものに基づいて、その正しい操作を推測できなければなりません。
この記事を最初に書いてから 3 年が経過しましたが、Java リフレクションを使用して、この問題に少し違ったアプローチを取り始めました。
ちょっとした秘密は、リフレクションを使用して、パブリック メソッドと同じように JUnit でプライベート メソッドをテストできることです。心ゆくまでテストしても、それらをクライアントに公開することはできません。
最も簡単な解決策は、JUnit テストを同じパッケージ (ただし異なるディレクトリ) に配置し、メソッドにデフォルト (つまり、パッケージ プライベート) の可視性を使用することです。
もう 1 つのより複雑な方法は、リフレクションを使用してプライベート メソッドにアクセスすることです。
比較的少数の「パブリック」エントリ ポイントに大量のロジックが埋め込まれている場合は、おそらく単一責任の原則に違反しています。可能であれば、コードを複数のクラスにリファクタリングして、最終的にテスト対象となる "パブリック" メソッドを増やすことをお勧めします。
これは、他の誰もがあなたを悩ませ続ける「おそらくこのようにすべきではない」方法です。しかし、このようにする理由があるのは確かに可能性の範囲内だと思います。次のコードはプライベートフィールドにアクセスしますが、プライベートメソッドのコードはほぼ同じです。
public void testPrivateField() throws InterruptedException {
Class<ClassWPrivateField> clazz = ClassWPrivateField.class;
try {
Field privateField = clazz.getDeclaredField("nameOfPrivateField");
privateField.setAccessible(true); // This is the line
// do stuff
} catch(NoSuchFieldException nsfe) {
nsfe.printStackTrace();
fail();
} catch(IllegalAccessException iae) {
iae.printStackTrace();
fail();
}
}
私はほぼ常に Java プロジェクトで Spring を使用しているため、私のオブジェクトは依存性注入用に構築されています。それらは、アプリケーション コンテキスト内で組み立てられるパブリック インターフェイスのかなり細かい実装になる傾向があります。そのため、クラス自体が十分に小さいため、プライベート メソッドをテストする必要はほとんどありません (あったとしても)。
Spring を使用しない場合でも、小さくて単純なオブジェクトをより大きくより大きな抽象化に組み立てるという同じプラクティスを採用する傾向があります。それぞれの抽象化は比較的単純ですが、集約されたオブジェクトによって複雑になります。
私の経験では、プライベート メソッドを単体テストする必要があるということは、テストしているものを単純化できる (そして単純化する必要がある) ことを示しています。
それは、あなたがまだ本当に必要性を感じているなら:
私は同じ問題に遭遇しました.「プライベートにする必要がある場合は、おそらくリファクタリングする必要があります」は、私には合いません。
クラスの内部で何らかの方法で分離したいある種の機能があるとします。たとえば、次のようなものがあるとします。
public class HolderOfSomeStrings{
private List<String> internal_values;
public List<String> get()
{
List<String> out = new ArrayList<String>();
for (String s:internal_values)
{
out.add(process(s));
}
return get;
}
private static String process(String input)
{
//do something complicated here that other classes shouldn't be interested in
}
}
ここでのポイントは、junit によって、プロセスを公開するか、少なくとも保護するか、独自のユーティリティ クラスに配置するように強制されることです。しかし、それが HolderOfSomeStrings の何らかの内部ロジックである場合、これが正しいかどうかは私にはまったくわかりません。これは非公開にする必要があり、見やすくすることで何らかの形でコードが台無しになるように思えます。
プライベート メソッドは (通常は) 別のパブリック メソッドを介して間接的にしかテストできないため、通常はテストしません。テスト運転中にプライベート メソッドを作成する場合、それらは通常、「メソッドの抽出」リファクタリングの結果であり、それまでにすでに間接的にテストされています。
多くのロジックを使用してプライベート メソッドをテストすることに懸念がある場合は、そのコードをパブリック メソッドの別のクラスに移動するのが最も賢明な方法です。それが完了すると、このコードを使用した以前の方法は、スタブまたはモックによって提供される機能を持つことでテストを簡素化できます。
Andy Hunt の考えを借りるには、プライベート メソッドであっても、関心のある何らかの副作用がなければなりません。つまり、これらのメソッドは、何らかのパブリック メソッドから呼び出され、オブジェクトの状態を変化させる興味深いタスクを実行する必要があります。 . その状態変化をテストします。
public メソッド pubMethod と private メソッド privMethod があるとします。pubMethod を呼び出すと、次に privMethod を呼び出してタスクを実行します (おそらく文字列の解析)。次に、pubMethod は、この解析された String を使用して、何らかの方法でメンバー変数の値を設定したり、独自の戻り値に影響を与えたりします。pubMethod の戻り値またはメンバー変数に対する目的の効果を監視してテストします (おそらくアクセサーを使用してアクセスします)。
メソッドがプライベートまたはパブリックであるかどうかを気にしないJUnitの代わりにTestNGを使用できます。
上記のようにリフレクションを使用して、プライベート メソッドをテストします。TDD に従っている場合は、TDD が後で驚きがないことを意味することを考えると、プライベート メソッドをテストする必要があります。したがって、プライベートをテストするための公開メソッドを完了するのを待つべきではありません。これは、リファクタリング時のより詳細な回帰テストに役立ちます。
「PrivateAccessor.invoke」を探します。私のコードは「junitx.util」からインポートしますが、どこから来たのかわかりません。
これの一種であり、「多言語プログラミング」の問題全体について誰もがどこに行き着くかはわかりませんが、Groovy テストは Junit で実行可能であり、パブリック/非パブリックの問題全体を無視します。ちなみに、正式には「バグ」として分類されていましたが、修正しようとしたところ、嵐が巻き起こり、元の状態に戻されました。
ほぼすべての投稿に同意して、おそらくリファクタリングする必要があり、パブリック以外でプライベートをテストしないでください。それについて別の考え方を追加したかっただけです...
クラス自体をメソッドではなく「ユニット」と考えてください。クラスをテストしており、パブリック メソッドの呼び出し方法に関係なく、クラスが有効な状態を維持できること。
プライベート メソッドを呼び出すと、カプセル化が破棄され、実際にテストが無効になる可能性があります。