Доступ к защищенному методу в тестовом примере с использованием Java Reflection - PullRequest
20 голосов
/ 12 января 2011

Я пытаюсь получить и вызвать защищенный метод, находящийся в другом классе, а также в другом пакете, используя 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()

Ответы [ 5 ]

25 голосов
/ 12 января 2011

Проблема с вашим кодом в том, что функция getDeclaredMethod ищет функцию как по имени, так и по типу аргумента. С звонком

Method retrieveItems = clazz.getDeclaredMethod("retrieveItems");

Код будет искать метод retrieveItems() без аргументов. Метод, который вы ищете, принимает аргумент, строку, поэтому вы должны вызвать

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

Это скажет Java для поиска retrieveItems(String), что вы и ищете.

6 голосов
/ 12 января 2011

Вместо использования этого хитрого отражения, почему бы просто не создать производный класс, у которого будет доступ к защищенному методу?

См. Является ли плохой практикой использование отражения в модульном тестировании? для дальнейших размышлений.

4 голосов
/ 12 января 2011

Если вы поместите свои тестовые наборы в один и тот же пакет (com.myapp вместо com.myapp.tests), они получат доступ к защищенным стандартным уровня пакета) членам.

Тогда вы можете позвонить service.retrieveMembers(status) напрямую.

Если вы пытаетесь отделить источник от тестов, обычно лучше использовать другой каталог с исходным кодом (например, каталог src и каталог test).

2 голосов
/ 02 марта 2017

Вы должны использовать ссылку на созданный объект вместо ссылки на класс в методе 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 голосов
/ 12 января 2011

Нет необходимости в отражении или наследовании:

Поместите ваш MyTestCase в пакет com.myapp, поскольку область действия 'protected' также является 'package'.Тогда MyTestCase может получить доступ к защищенным методам MyServiceImpl.

...