2016-04-11 11 views
1

単体テストについてはthis answerラッパーメソッドを読んでいます。次のコードで:それは私がmethodB()のすべての機能が、単なるテストmethodB()がすでにテストする必要がありますのでargがnullではないです2例をテストする必要がないことを合理的に見える基本メソッドがプライベートの場合の単体テストラッパーメソッド

public static Object methodA(Object arg) { 
    if (arg == null) { 
     return null; 
    } else { 
     return methodB(); 
    } 
} 

methodB()プライベート方法であれば

しかし、私はanother answerによると、プライベートメソッドは実装の詳細なので、methodB()が提供するすべての機能をテストする必要があります。

public static MyObject methodA1(int x) { 
    MyObject obj = new MyObject(); 
    obj.setX(x); 
    return methodB(obj); 
} 

public static MyObject methodA2(int y) { 
    MyObject obj = new MyObject(); 
    obj.setY(y); 
    return methodB(obj); 
} 

private static MyObject methodB(MyObject obj) { 
    // doSomething with obj 
    return obj; 
} 

私は別にmethodA1()methodA2()をテストする必要があります:私は2つの方法methodA1()methodA2()を持っており、それらはすべて、このような呼び出しmethodB()場合

問題は、ありますか? methodA1()methodA2()methodB()の単なるラッパー・メソッドなので、methodB()が正しくテストされている場合、私は全くmethodA1()methodA2()をテストする必要はありませんので、または私はちょうどプライベートメソッドmethodB()をテストすることができます。

編集:

パブリックメソッドのテストは、最初に書きました。しかし、問題は、methodAのバリエーションが多数あり、その中にいくつかの機能/要件が共有されている場合、テストケースのコードが複製されることです。だから私はプライベートメソッドmethodB()をテストすべきかどうか疑問に思っています。

私が実際に遭遇した問題は、データベースにレコードを追加するという要件があり、提供すべきさまざまなAPIがたくさんあることです。

MyObject addMale(String name, String job);  // fill sex with "Male" 
MyObject addStudent(String name, String sex); // fill job with "Student" 

を、それらのすべては、パラメータが有効であるかどうかチェックし、指定されたし、実際にそうであるデータベースの中にレコードを挿入するためにプライベートメソッドを呼び出していないフィールドを入力します。たとえば、私が提供しなければなりませんmethodB()と呼ばれます。

このようなAPIがたくさんあるので、すべてのフィールドの状況でmethodB()しかテストできない場合は、おそらく私はテストケースの重複を減らすことができますが、このようなユニットテストを行うのは良い方法ですか?

EDIT2:

私は、私は私の他のテストケースで反射を使用するので、私はプライベートメソッドをテストすることができます知っている、と私はそれがあまりにも、プライベートメソッドを呼び出すことができます知っています。しかし、私の質問は、この状況では、プライベートメソッドをテストすることが適切な解決策であるかどうかです。

+0

'methodA1'が' methodA2'と異なる何かをする場合、明らかに別のテストが必要です。両方のメソッドが同じことをする場合は、1つのメソッドだけが必要です。 – AJNeufeld

+0

ビットを展開する: 'methodA1'はオブジェクトに** setX' **を呼び出し、' methodB'に渡します。ここで 'methodA2'はオブジェクトに対して** setY' **を呼び出し、' methodB'に渡します。 。 'methodB'の動作は、オブジェクトの' X'がセットされているのか、 'Y'がセットされているのかによって異なります。どちらもテストする必要があります。 'methodB'をテストしたばかりの場合は、どちらの場合でもテストケースを記述する必要があります。 A1とA2の両方のテストケースを記述することで、明らかにすることもできます。 – AJNeufeld

+0

単体テストのコードカバレッジ解析を実行すると、 'methodA'と' methodA2'の単体テストを 'methodB'の代わりに実行した方が、カバレッジが向上します。 – AJNeufeld

答えて

1

これは実際に私がしばらく疑問に思っていた質問ですが、必ずしも正しいとは限りませんが、私は意見を共有します。

主な問題は、プライベートメソッドはテストするのが難しいということです。私はいくつかのグーグルで、いくつかのツールやテクニックを使ってプライベートメソッドにアクセスしましたが(反射が私が遭遇した主なものです)、少し畳み込まれたようでした。

しかし、あなたがプライベートメソッドを書いた理由は、それを呼び出すパブリックメソッドである別のメソッドがあるからです。そのため、プライベートメソッドを直接テストすることはできませんが、それを呼び出すパブリックメソッドをテストすることで、その機能をチェックできます。

私があなただったら、私は広範囲にmethodB()のすべての機能を使用すると、パブリックメソッドで実行するテストによってテストされることを保証し、methodA1()methodA2()をテストします。

+0

'methodA1()'と 'methodA2()'の間で共有されている 'methodB()'の機能がある場合は、どこでテストする必要がありますか?私が両方でテストすると、私のテストケースが複製され、私がそのテストケースの1つでテストすると、どのテストケースにもテストが出現する可能性があるため、維持するのが難しくなります。 – Nier

+1

Imho、あなたは 'methodA1()'と 'methodA2()' *を完全に*テストするべきです(そこに入る可能性のある入力を意味します - 純粋に内部的なものであれば、それが何らかの公開APIである場合よりも少なくなる可能性があります)。 'methodA2()'の50%しかテストしない(他の50%は 'methodA1()'と同じです)*致命的なことがありますか? 'methodA2()'が変わるとすぐに、それは突然50%テストされないかもしれません。別々の単体テストがある場合は、少なくとも単体テストが以前と同じように動作することを保証します。 –

+0

@FlorianSchaetz意見をいただきありがとうございます。あなたは最後の編集で追加した最後の段落を見ましたか? 'methodA()'のバリエーションが複数あり、それらが共通の 'methodB()'を共有していたらどうなりますか?例えば、名前が空であり、名前が無効であり、名前がヌルであり、ジョブが空である...などであり、これらの重複したコードは多くの 'methodA'テストケースに広がっています。 'methodB()'でそれらをテストできれば、テストケースで重複したコードを減らすことができます。このような状況では、private 'methodB()'の単体テストは依然として不適切な解決策と考えられますか? – Nier

1

methodA1()methodA2()の単体テストを書くべき理由がいくつかあります。あなたはそれらに押し戻してきました。あなたはここで質問しました。あなたは彼らのために完全な単体テストを書いていないという正当な理由があることをはっきりと見ています。私たちはあなたにあなたが望む答えを与えることができるかどうかを見てみましょう。 ;-)

編集で追加したものから、ビルダーパターンにバリエーションがあるようです。例)

MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build(); 

ビルダーをテストするにはどうすればよいですか?

ビルダーには4つの属性があります(任意の順序で設定できます)。 = 24の異なる順序。完全なテストスイートには、次のものを含める必要があります:

@Test public void testXYZW() { ... } 
@Test public void testXYWZ() { ... } 
// ... 21 more permutations ... 
@Test public void testWZYX() { ... } 

これはすべてですか?いいえ!これらの属性の中にはデフォルト値を持つものもあるので、それらのパターンもテストする必要があります。合計順序は、今P(4,4)+ P(4,3)+ P(4,2)+ P(4,1)+ P(4,0)= 24 + 24 + 12 + 4 + 1 = 85単体テスト。

@Test public void testXWY() { ... } 
@Test public void testWY() { ... } 
@Test public void testZ() { ... } 
// ... 61 more permutations ordering 

そして、これが唯一のX、Yの各順列をテストし、Zは、Wは、テストごとに属性ごとにテスト値を持つ属性。すべての可能な組み合わせと順列に対して包括的なテストセットを書くことは明らかに扱いにくいです。

ビルダークラスのデザイナーは、属性設定の順列が結果の構造に影響しないことを理解しています。注文の順列のためのテストを書くことは、実際にテストカバレッジを増加させない。省略された属性のテストは、デフォルト値をテストするときに便利です。省略された属性の異なる組み合わせをテストしても、テストカバレッジは向上しません。だから、慎重に考えた後、2つだけのテストが必要になることがあります:

@Test 
public void testXYZW() { 
    MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build(); 
    assertThat(o.wasBuiltProperly()); 
} 

@Test void testDefaults() { 
    MyObject o = new Builder().build(); 
    assertThat(o.wasBuiltProperlyFromDefaults()); 
} 

methodB()の適切な、完全なテストが行​​われている場合は、安全にテストをmethodA1()methodA2()での入力の検証のみを離れて得ることができます。

@Test void testMethodA1Professor() { 
    MyObject o = methodA1("professor"); 
    assertThat(o.wasBuiltProperlyWithProfessor()); 
} 

@Test void testMethodA1WithNull() { 
    MyObject o = methodA1(null); 
    assertThat(o.wasBuiltProperlyWithNull()); 
} 
0

多くの場合、プライベートメソッドがクラス内の複数のメソッドによって使用される場合、背後に隠れる明確な概念があります。それは独自のクラスを持つ価値があるかもしれません。

    :あなたはあなたの公開APIの一部として、それを利用できるようにする独自のクラスに methodBを抽出しませんでしたいくつかの方法があります

    クラスの外でそれが使用されるべきではない

    それを使用して、クラス内の

  • 巣は

  • がLoで別のモジュールに入れてそれに制限された範囲を与えますレベル。そのモジュールをAPIから利用できるようにしますが、クライアントからは利用できないようにします。

+0

'methodB'がそれ自身のクラスにふさわしい理由について、より詳細な情報を与えることができますか? 'methodB'は単なるprivateメソッドであれば正常に動作するので、別のクラスに移動することのメリットが分かりません。 – Nier

+0

私の答えでは* andtentimes *と* may *という単語に注意してください。私はそれが自分のクラスに値すると断言しない。あなただけが知る知識があります。 – guillaume31

+0

これはうまく動作しているかどうかに関係なく、クラス内の結束の問題です。 [単元責任原則](https://en.wikipedia.org/wiki/Single_responsibility_principle)は、 'methodB'が残りの部分と十分に独立しているため、クラスに2つの理由がある場合は、2つに分割する必要があることを示しています。 1クラス= 1コンセプト。 2つの概念= 2つのクラス。 – guillaume31

関連する問題