Вопрос-ответ

How do I test a class that has private methods, fields or inner classes?

Как мне протестировать класс, который имеет закрытые методы, поля или внутренние классы?

Как мне использовать JUnit для тестирования класса, который имеет внутренние закрытые методы, поля или вложенные классы?

Кажется неправильным изменять модификатор доступа для метода только для того, чтобы иметь возможность запустить тест.

Переведено автоматически
Ответ 1

Если у вас есть несколько устаревшее приложение на Java, и вам не разрешено изменять видимость ваших методов, лучший способ протестировать закрытые методы - использовать отражение.

Внутри мы используем помощники для получения / установки private и private static переменных, а также для вызова private и private static методов. Следующие шаблоны позволят вам делать практически все, что связано с частными методами и полями. Конечно, вы не можете изменять private static final переменные с помощью отражения.

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

И для полей:

Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);


Примечания:



  1. TargetClass.getDeclaredMethod(methodName, argClasses) позволяет изучить private методы. То же самое относится к getDeclaredField.

  2. setAccessible(true) Требуется для работы с закрытыми методами.


Ответ 2

Лучший способ протестировать закрытый метод - использовать другой открытый метод. Если это невозможно сделать, то выполняется одно из следующих условий:


  1. Закрытый метод - это мертвый код

  2. В тестируемом классе чувствуется запах дизайна

  3. Метод, который вы пытаетесь протестировать, не должен быть закрытым

Ответ 3

Когда у меня есть закрытые методы в классе, которые достаточно сложны, что я чувствую необходимость протестировать частные методы напрямую, это пахнет кодом: мой класс слишком сложный.

Мой обычный подход к решению таких проблем заключается в создании нового класса, который содержит интересные фрагменты. Часто этот метод и поля, с которыми он взаимодействует, и, возможно, еще один или два метода могут быть извлечены в новый класс.

Новый класс предоставляет эти методы как "общедоступные", поэтому они доступны для модульного тестирования. Новый и старый классы теперь оба проще, чем исходный класс, что для меня здорово (мне нужно упростить работу, иначе я заблужусь!).

Обратите внимание, что я не предлагаю людям создавать классы, не используя свой мозг! Смысл здесь в том, чтобы использовать возможности модульного тестирования, которые помогут вам найти хорошие новые классы.

Ответ 4

Я использовал отражение, чтобы сделать это для Java в прошлом, и, на мой взгляд, это было большой ошибкой.

Строго говоря, вам не следует писать модульные тесты, которые напрямую тестируют закрытые методы. Что вы должны тестировать, так это публичный контракт, который класс имеет с другими объектами; вы никогда не должны напрямую тестировать внутренние компоненты объекта. Если другой разработчик хочет внести небольшое внутреннее изменение в класс, которое не влияет на публичный контракт классов, он / она должен изменить ваш тест на основе отражения, чтобы убедиться, что он работает. Если вы делаете это неоднократно на протяжении всего проекта, модульные тесты перестают быть полезным измерением работоспособности кода и начинают становиться помехой в разработке и раздражением для команды разработчиков.

Вместо этого я рекомендую использовать инструмент покрытия кода, такой как Cobertura, чтобы убедиться, что модульные тесты, которые вы пишете, обеспечивают достойное покрытие кода частными методами. Таким образом, вы косвенно тестируете, что делают закрытые методы, и поддерживаете более высокий уровень гибкости.

java unit-testing junit