多くのアプリケーションでは、専用のサブアルゴリズム(または単に明確に定義されたコード)を利用するアルゴリズムを使用することがよくあります。
これまで、メインアルゴリズムを作成したときに、以下の例(OldStyle)のように、サブアルゴリズムごとにプライベートメソッドを作成しました。
public class OldStyle {
public int mainAlg() {
int x = subAlg01();
int y = subAlg02();
int z = x * y;
return z;
}
private int subAlg01() {
return 3;
}
private int subAlg02() {
return 5;
}
}
これは問題なく機能しましたが、プライベートであっても1つのメソッド(mainAlg)でのみ使用されるメソッド(subAlg01とsubAlg02)が急増するのは好きではありませんでした。
最近、ローカル内部クラスの使用を発見しました。今、私の例は(NewStyle)です。
public class NewStyle {
public int mainAlg() {
class Nested {
public int subAlg01() {
return 3;
}
public int subAlg02() {
return 5;
}
}
Nested n = new Nested();
int x = n.subAlg01();
int y = n.subAlg02();
int z = x * y;
return z;
}
}
私はそれがとても好きですが、今私は次の問題を抱えています:JUnitを使用してsubAlg01とsubAlg02をテストするにはどうすればよいですか?
ちなみに、私はEclipseを使用しています。
助けてくれてありがとう。
編集:もっとよく説明しようとしています:たとえば、並べ替えアルゴリズムがあり、期待どおりに実行されることを確認するためにテストしたいと思います。このソートアルゴリズムは、クラスXのメソッドmでのみ使用されます。クラスXのプライベートメソッドにすることはできますが、クラスXは通常、ソートとは関係ありません。なぜ、クラスXをソートメソッドで「台無しにする」のでしょうか。だから私はそれをメソッドmの中に入れました。しばらくして、並べ替えアルゴリズムを改善したい(高速化したい)が、動作が期待どおりであることを確認したいので、元のテストで再テストしたい。
それが私がやりたいことです。解決策がないかもしれません。誰かが私を助けてくれることを願っています。
回答の選択後に編集。ロドニーの答えを選んだのは、彼の解決策が私が採用したものだからです。スタンドアロンのヘルパークラスは、サブメソッドが何であるかを明確に把握するのに役立ち(ヘルパーです!)、それらをテストする機能も提供します。
フィリッポ、私はあなたの問題といくつかの答えに対する欲求不満を理解しています。何年も前に初めてJUnitを使い始めたとき、私もプライベートコードをテストしたかったので、それが悪い考えだと言うのは馬鹿げていると思いました。
彼らは正しかったことがわかりました(驚きです!)が、かなりの数のテストを書いた後で初めて、私は理解しましたなぜ。同じプロセスを経る必要があるかもしれませんが、最終的には同じ結論に達します;-)
とにかく、あなたの状況では、私はNested
を適切なスタンドアロンクラスにし、おそらくそれがヘルパークラスであることを明らかにするために別のパッケージにします。次に、他のテストとは関係なく、直接テストを作成します。
次に、NewStyle
のテストを作成し、NewStyle
の動作のみに焦点を当てます。
(おそらく、Nested
内でインスタンス化するのではなくNewStyle
をNewStyle
に挿入します。つまり、NewStyle
のコンストラクターへの引数にします。
次に、テストでNewStyle
のテストを作成するときに、Nested
のインスタンスに合格して続行します。特に注意が必要な場合は、Nested
からインターフェイスを作成し、2番目の実装を作成し、それを使用してNewStyle
もテストします。)
クラスのパブリックインターフェイスのみをテストする必要があり、プライベートメンバーやプライベート内部クラスはテストしないでください。プライベートメンバーは、実装の詳細であり、クラスのパブリックメソッドによってのみ(直接的または間接的に)使用されます。したがって、呼び出し元のメソッドを介して間接的にこれらを単体テストできます。これらの単体テストで十分な粒度がないと感じた場合、または関心のある結果(の一部)を感知できない場合、これはおそらく設計に問題があることを示しています。クラスが大きすぎる可能性があります。やりすぎると、その機能の一部を別のクラスに抽出する必要があり、そこで直接単体テストを行うことができます。
現在の例では、内部クラス自体に多くのコードが含まれている場合は、それをトップレベルクラスに変換するだけで、そのメソッドを直接単体テストできます。
(ところで、それが囲んでいるクラスインスタンスを参照する必要がない場合、内部クラスはstatic
である必要があります。)
実際には、ローカルの内部クラスをテストできます。ただし、インターフェイスを実装する必要があります。このようにして、リフレクションを介してローカルクラスのインスタンスを作成し、それをそのインターフェイスにキャストできます。インターフェイスタイプを取得したら、問題なく実装コードをテストできます。
インターフェース:
public interface Algorithm {
int subAlg01();
int subAlg02();
}
クラス:
public class NewStyle {
public int mainAlg() {
class Nested implements Algorithm {
public int subAlg01() {
return 3;
}
public int subAlg02() {
return 5;
}
}
Nested n = new Nested();
int x = n.subAlg01();
int y = n.subAlg02();
int z = x * y;
return z;
}
}
テスト:
public class NewStyleTest {
@Test
public void testLocal() throws ClassNotFoundException,
NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
Class<?> forName = Class.forName("NewStyle$1Nested");
Constructor<?> declaredConstructor = forName
.getDeclaredConstructor(NewStyle.class);
declaredConstructor.setAccessible(true);
Algorithm algorithm = (Algorithm) declaredConstructor
.newInstance(new NewStyle());
assertEquals(algorithm.subAlg01(), 3);
assertEquals(algorithm.subAlg02(), 5);
}
}
これらのクラスには外部から到達できないため、junitはそれらをテストできません。それらをテストするには、公開されているものが必要です。
理由だけでコードを複雑にしすぎないようにする必要があります
メソッドが急増するのは好きではありません
あなたの場合、メソッドが外部クラスのメソッドであるかどうか、または内部クラスがどうしても必要な場合は、mainAlg()メソッドの外部に配置して、グローバルに表示できるようにすることができます。
_public class NewStyle {
public int mainAlg() {
Nested n = new Nested();
int x = n.subAlg01();
int y = n.subAlg02();
int z = x * y;
return z;
}
class Nested {
public int subAlg01() {
return 3;
}
public int subAlg02() {
return 5;
}
}
}
_
これは、new NewStyle().new Nested().subAlg01();
を使用して呼び出すことができます。
この問題は、内部クラスの動作がメソッドの動作のコア部分である場合に発生します。メソッドがあるとすると、実行可能オブジェクトを3番目のオブジェクトに渡すことになっています。これは、実際にはそうではない内部クラスです。別のエンティティ:この場合、適切な単体テストでは、3番目のオブジェクトをモックして内部クラスを実行し、引数キャプチャを使用してテストする必要があります。
この種の問題は、関数型プログラミングをより多くサポートしている言語で非常に一般的であり、サードパーティに渡されたラムダのテストがほとんどの要件です。
ただし、前に述べたように、内部クラスが外部の関係者によって使用されない場合、それは単なる実装の詳細であり、個別にテストすることは役に立ちません。
うーん、Groovyのような言語はJavaで単体テストを行うためによく使用され、プライベートフィールドとメソッドに透過的にアクセスできることを知っています.....しかし、ネストされたクラスについてはよくわかりません。なぜこのようなことをしたいかは理解できますが、ゲッターとセッターのテストと同じ立場をとっています。パブリックメソッドをテストすることの副作用としてテストする必要があります。そうでない場合は、そのようにテストされたら、なぜ彼らはそもそもそこにいるのですか?