2011-01-12 11 views
19

Java Reflectionを使用して、異なるクラスおよび異なるパッケージに存在する保護されたメソッドを取得して呼び出しようとしています。保護されたメソッドを含むJava Reflectionを使用したテストケースでの保護されたメソッドへのアクセス

クラス:

package com.myapp; 

public class MyServiceImpl { 

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

呼び出すクラスは:

java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems() 

がこれを読むために時間を割いていただき、ありがとうございます:

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"); 
    } 
} 

コンパイラは、この例外がスローされます。

答えて

23

コードの問題は、getDeclaredMethod関数が名前と引数型の両方で関数をルックアップすることです。電話で

このコードでは、引数なしのretrieveItems()が検索されます。あなたが探しているメソッドは、引数、文字列がかかりますので、あなたは、あなたが探しているものである、retrieveItems(String)を検索するためのJavaを教えてくれます

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

これを呼び出す必要があります。

+0

1 - これは、例外がある問題であり、フラグを立てる。メソッドを取得したら、@ jkの答えに従ってアクセス可能にする必要があります。 –

6

このトリッキーな反射物を使用する代わりに、保護されたメソッドにアクセスする派生クラスを作成するだけではどうですか?

さらなる考え方については、Is it bad practice to use Reflection in Unit testing?を参照してください。

+0

+1 - これはもっと賢明なアプローチです、IMO。 –

+1

-1 - 根本的な質問には答えません。 Javaでリフレクションして保護されたメソッドにアクセスするにはどうすればよいですか? – BrainSlugs83

+0

@ BrainSlugs83質問のタイトルを読み返してください。OPは実際にはいくつかのコードをテストしたいと思いますが、誤ってリフレクションを使う必要があると考えています。彼らにはXY問題があります。私の答えは、提案されている解決策ではなく、実際の問題を話します。 – Raedwald

2

あなたは、彼らが保護(およびデフォルトパッケージレベル)のメンバーにアクセスする必要があります(com.myapp代わりcom.myapp.testsの)同じパッケージであなたのテストケースを置く場合。

次に、service.retrieveMembers(status)に直接電話することができます。

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

はスコープ「保護された」として、あなたのMyTestCase下のパッケージcom.myappを入れても「パッケージ」です:

+0

テストが同じパッケージに含まれている場合、コンパイルされたクラスファイルは同じターゲットディレクトリに存在する可能性が最も高くなります。テストパッケージファイルを含む展開ファイルは膨大になります。ターゲットディレクトリの除外ルールを定義します。私の意見では良い考えではありません。 –

+0

そのため、テストには別のソースディレクトリを使用します。それが、標準的な方法です。 – Nick

+0

ええ、私はあなたの投稿を誤解しました。私は今あなたが言っていることを見ます、ありがとう! –

2

ない反射や継承が必要とされています。 MyTestCaseは、MyServiceImplの保護されたメソッドにアクセスできます。

+0

テストが同じパッケージに含まれている場合、コンパイルされたクラスファイルは同じターゲットディレクトリに存在する可能性が高くなります。テストパッケージファイルを含む展開ファイルは膨大になります。ターゲットディレクトリの除外ルールを定義します。私の意見では良い考えではありません。 –

+0

@SandySimonton、それは達成することができます。プロジェクトの構造は次のようにすることができます(maven): 'src-> main-> java'はすべてのコードを含んでいます。 'src-> test-> java'にはすべてのテストが含まれています。 –

2
あなたはinvokeメソッドに代わりにクラスへのリンクの作成されたオブジェクトへのリンクを使用してロック解除のアクセスにMethod.setAccessible(真の)呼び出しを使用するようにすべきである

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"); 
} 
関連する問題