web-dev-qa-db-ja.com

テストクラスに対してのみプライベートメソッドをパブリックにするアノテーション

その共通のニーズに対応するソリューションを持っている人。

アプリケーションにクラスがあります。

aPIの一部であるため、一部のメソッドはパブリックであり、一部は内部フローを読みやすくするための内部使用のためにプライベートである

今、私はユニットテスト、または統合テストのようなものを書きたいと言います。これは別のパッケージに配置され、このメソッドを呼び出すことができますが、このメソッドの通常の呼び出しは許可されませんアプリケーション自体のクラスから呼び出そうとした場合

だから、私はそのようなことを考えていました

public class MyClass {

   public void somePublicMethod() {
    ....
   }

   @PublicForTests
   private void somePrivateMethod() {
    ....
   }
}

上記のアノテーションは、プライベートメソッドを「テスト用にパブリック」としてマークします。つまり、テストおよびパッケージの下にあるすべてのクラスでコンパイルおよびランタイムが許可されますが、コンパイルおよび/またはランタイムはテストパッケージの下ではありません。

何かご意見は?このような注釈はありますか?これを行うためのより良い方法はありますか?

ユニットテストを書くほど、カプセル化を破るように強制されるようになります...

80
Kumetix

一般的な方法は、privateメソッドをprotectedまたはpackage-privateにして、このメソッドの単体テストをテスト対象のクラスと同じパッケージに入れることです。グアバには @VisibleForTestingアノテーション がありますが、これはドキュメント作成のみを目的としています。

118
JB Nizet

テスト対象クラス内のすべてのパブリックメソッドでテストカバレッジが良好な場合、すべての可能なケースをアサートするため、パブリックメソッドによって呼び出されるプライベートメソッドは自動的にテストされます。

JUnit Docには次のように書かれています:

プライベートメソッドのテストは、再利用性を促進するために、それらのメソッドを別のクラスに移動する必要があることを示す場合があります。ただし、必要な場合... JDK 1.3以上を使用している場合、リフレクションを使用して、PrivilegedAccessorを使用してアクセス制御メカニズムを破壊できます。使用方法の詳細については、 この記事をお読みください

21
Cygnusx1

インターフェースを使用してAPIメソッドを公開すること、ファクトリーまたはDIを使用してオブジェクトを公開することを検討して、消費者がインターフェースのみでそれらを認識できるようにします。インターフェースは公開されたAPIを記述します。そうすれば、実装オブジェクト上で公開したいものを何でも作成でき、それらの消費者はインターフェースを通じて公開されたメソッドのみを見ることができます。

10
Nathan Hughes

dp4j には必要なものがあります。基本的に、クラスパスにdp4jを追加するだけで、@ Test(JUnitのアノテーション)アノテーションが付けられたメソッドがプライベートなメソッドを呼び出すたびに動作します(dp4jはコンパイル時に必要なリフレクションを注入します)。 dp4jの@TestPrivatesアノテーションを使用して、より明示的にすることもできます。

プライベートメソッドにも注釈を付けることを主張する場合は、Googleの@VisibleForTesting注釈を使用できます。

5
simpatico

または、このメソッドをいくつかのstrategyオブジェクトに抽出できます。この場合、抽出されたクラスを簡単にテストでき、メソッドをpublicにしたり、リフレクション/バイトコードで魔法をかけたりしないでください。

2
Stan Kurilin

プライベートメソッドのテスト に関する記事には、プライベートコードをテストするためのいくつかのアプローチが記載されています。リフレクションを使用すると、リファクタリングが行われたかどうかを覚えておくためにプログラマに余分な負担がかかり、文字列は自動的に変更されませんが、最もクリーンなアプローチだと思います。

2
Atreys

あなたはこれを行うことができません。コンパイラは注釈を考慮しません。

これには2つの一般的なアプローチがあります

最初はリフレクションを使用してとにかくメソッドにアクセスすることです

2つ目は、privateではなくpackage-privateを使用し、テストを同じパッケージ(ただし、異なるモジュール)で行うことです。これらは基本的に他のコードに対してプライベートですが、テストは引き続きそれらのコードにアクセスできます。

もちろん、ブラックボックステストを行う場合は、とにかくプライベートメンバーにアクセスしないでください。

1
Joeri Hendrickx

わかりましたので、ここで私たちは混合されている2つのものがあります。最初に、テストでのみ使用するものをマークする必要がある場合は、@ JB Nizetに同​​意します。グアバアノテーションを使用すると良いでしょう。

別のことは、プライベートメソッドをテストすることです。外部からプライベートメソッドをテストする必要があるのはなぜですか?つまり、オブジェクトをパブリックメソッドでテストし、最後にその動作をテストできるはずです。少なくとも、私たちは、(良い習慣として)プライベートメソッドを常にテストしようとするジュニア開発者に教えており、教えようとしていることです。

1
facundofarias

私たちは最近、リフレクションを介してプライベートフィールド、メソッド、内部クラスにアクセスするのに役立つライブラリをリリースしました: BoundBox

のようなクラスの場合

public class Outer {
    private static class Inner {
        private int foo() {return 2;}
    }
}

次のような構文を提供します。

Outer outer = new Outer();
Object inner = BoundBoxOfOuter.boundBox_new_Inner();
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo();

BoundBoxクラスを作成するために必要なことは、@BoundBox(boundClass=Outer.class)BoundBoxOfOuterクラスを作成することだけです。

1
Snicolas

私はそのような注釈を知りませんが、以下は価値があるかもしれません: ユニットテストプライベートメソッド
または以下: JMockit

1
Woot4Moo

私はそれを内部クラスにして、クラス自体にテストを配置しました。 http://www.ninthavenue.com.au/how-to-unit-test-private-methods

0
Roger Keays

私が知っている限りでは、このような注釈はありません。最良の方法は、他のいくつかが示唆したように、反射を使用することです。この投稿を見てください:
プライベートメソッド、フィールド、または内部クラスを持つクラスをテストするにはどうすればよいですか?

メソッドの例外結果のテストにのみ注意する必要があります。たとえば、IllegalArgumentExceptionが予期されるが、代わりに「null」(Class:Java.lang.reflect.InvocationTargetException)が発生する場合。
私の同僚は、これらの状況で powermock framework を使用することを提案しましたが、まだテストしていないので、それが正確に何ができるのか分かりません。私はMockitoフレームワークを使用してきましたが、Mockitoフレームワークは優れたフレームワークでもあります(ただし、プライベートメソッドの例外の問題は解決しないと思います)。

@PublicForTestsアノテーションを持っているのは素晴らしいアイデアです。

乾杯!

0
despot