web-dev-qa-db-ja.com

Java Reflectionを使用して、テストケースで保護されたメソッドにアクセスする

Java Reflectionを使用して、別のクラスおよび別のパッケージにある保護されたメソッドを取得して呼び出しようとしています。

保護されたメソッドを含むクラス:

package com.myapp;

public class MyServiceImpl {

   protected List<String> retrieveItems(String status) {
         // Implementation
   }
}

呼び出しクラス:

package xxx.myapp.tests;

import com.myapp.MyServiceImpl;

public class MyTestCase {

    List<String> items;

    public void setUp() throws Exception {

         MyServiceImpl service = new MyServiceImpl();
         Class clazz = service.getClass();

         // Fails at the next line:
         Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");

         // How to invoke the method and return List<String> items?
         // tried this but it fails?
         retrieveItems.invoke(clazz, "S");
    }
}

コンパイラは次の例外をスローします。

Java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems()
20
PacificNW_Lover

コードの問題は、getDeclaredMethod関数が名前と引数タイプの両方で関数を検索することです。電話で

_Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");
_

コードは、引数のないメソッドretrieveItems()を探します。あなたが探しているメソッドは引数、文字列を取るので、あなたは呼び出す必要があります

_Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
_

これにより、JavaはretrieveItems(String)を検索するように指示されます。これは、探しているものです。

25
templatetypedef

そのトリッキーなリフレクションを使用する代わりに、保護されたメソッドにアクセスできる派生クラスを作成してみませんか?

詳細については、 ユニットテストでReflectionを使用するのは悪い習慣ですか? を参照してください。

6
Raedwald

テストケースを同じパッケージ(_com.myapp_ではなく_com.myapp.tests_)に入れると、テストケースはprotected(およびdefaultパッケージレベル)メンバーにアクセスできるようになります。 。

次に、service.retrieveMembers(status)を直接呼び出すことができます。

ソースをテストから分離しようとしている場合は、通常、別のソースディレクトリ(たとえば、srcディレクトリとtestディレクトリ)を使用することをお勧めします。

4
Nick

リフレクションや継承は必要ありません:

スコープ「protected」も「package」であるため、MyTestCasepackagecom.myappの下に置きます。次に、MyTestCaseMyServiceImplの保護されたメソッドにアクセスできます。

Invokeメソッドのクラスへのリンクではなく、作成されたオブジェクトへのリンクを使用し、ロック解除アクセスにMethod.setAccessible(true)呼び出しを使用する必要があります。

public void setUp() throws Exception {
    MyServiceImpl service = new MyServiceImpl();
    Class<?> clazz = service.getClass();
    Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class);
    retrieveItems.setAccessible(true);
    items = (List<String>)retrieveItems.invoke(service, "S");
}
2
BeCase