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

Как выполнить модульное тестирование (с использованием xUnit) класса, который имеет внутренние закрытые методы, поля или вложенные классы? Или функция, которая делается частной благодаря наличию внутренней связи ( staticв C / C ++) или находится в закрытом ( анонимном ) пространстве имен?

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

29.08.2008 16:11:09
Лучший способ проверить приватный метод - это не тестировать его напрямую
Surya 30.08.2010 20:43:56
Mouna Cheikhna 13.10.2010 09:34:01
Я не согласен. (Публичный) метод, который является длинным или трудным для понимания, должен быть реорганизован. Было бы глупо не проверять маленькие (приватные) методы, которые вы получаете вместо общедоступных.
Michael Piefel 25.10.2011 07:16:17
Не тестировать какие-либо методы только потому, что это видимость глупо. Даже модульное тестирование должно быть наименьшим фрагментом кода, и если вы тестируете только общедоступные методы, вы никогда не будете точно знать, где произошла ошибка - тот или иной метод.
Dainius 3.08.2012 11:35:12
Вам нужно проверить функциональность класса , а не его реализацию . Хотите проверить частные методы? Протестируйте публичные методы, которые их вызывают. Если функциональность, предлагаемая классом, тщательно протестирована, его внутренняя часть продемонстрировала правильность и надежность; Вам не нужно проверять внутренние условия. Тесты должны выдерживать отделение от тестируемых классов.
Calimar41 11.04.2014 11:19:13
30 ОТВЕТОВ
РЕШЕНИЕ

Обновить:

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

@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;

Таким образом, ваш код остается безопасным и читабельным. Никаких компромиссов в дизайне, никаких переэкспонированных методов и полей для испытаний.

Если у вас есть какое-то устаревшее 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)Требуется тренироваться с рядовыми.

1622
15.03.2019 02:50:55
Полезно, если вы, возможно, не знаете API, но если вам приходится тестировать закрытые методы таким образом, то с вашим дизайном что-то не так. Как говорит другой автор, модульное тестирование должно проверять контракт класса: если контракт слишком широкий и создает слишком большую часть системы, тогда следует рассмотреть проект.
andygavin 26.06.2009 14:23:29
Очень полезный. При использовании этого важно помнить, что он будет плохо работать, если тесты будут выполняться после обфускации.
Rick Minerich 4.02.2010 01:11:36
Пример кода не работает для меня, но это сделало Thigs более понятным: java2s.com/Tutorial/Java/0125__Reflection/…
Rob 1.07.2011 10:56:50
Намного лучше, чем использовать прямое отражение, было бы использовать какую-то библиотеку для него, например Powermock .
Michael Piefel 25.10.2011 07:22:54
Вот почему Test Driven Design полезен. Это поможет вам выяснить, что нужно подвергать воздействию, чтобы проверить поведение.
Thorbjørn Ravn Andersen 18.07.2013 18:46:25

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

  1. Закрытый метод - мертвый код
  2. Рядом с классом, который вы тестируете, ощущается запах дизайна
  3. Метод, который вы пытаетесь проверить, не должен быть закрытым
609
29.08.2008 16:14:19
Более того, мы никогда не приближаемся к 100% охвату кода, так почему бы не сосредоточить свое время на тестировании качества на методах, которые клиенты будут использовать напрямую.
grinch 13.02.2013 20:29:10
@ Гринч Пятно на. Единственное, что вы получите от тестирования частных методов, - это отладка информации, и для этого нужны отладчики. Если ваши тесты по контракту класса имеют полное покрытие, то у вас есть вся необходимая информация. Частные методы - это детали реализации . Если вы их тестируете, вам придется менять свои тесты каждый раз, когда меняется реализация, даже если контракт этого не делает. В полном жизненном цикле программного обеспечения это, вероятно, будет стоить намного больше, чем выгода, которую это дает.
Erik Madsen 25.06.2013 07:53:36
@ AlexWien ты прав. Покрытие было не правильным термином. То, что я должен был сказать, было «если ваши тесты контракта класса охватывают все значимые входы и все значимые состояния». Это, как вы правильно заметили, может оказаться невозможным для тестирования через открытый интерфейс к коду или косвенно, как вы на него ссылаетесь. Если это относится к некоторому коду, который вы тестируете, я бы подумал: (1) контракт слишком щедрый (например, слишком много параметров в методе) или (2) контракт слишком расплывчат (например, поведение метода) сильно зависит от класса государства). Я бы рассмотрел оба дизайна запахов.
Erik Madsen 2.07.2013 15:33:37
Практически все частные методы не должны подвергаться непосредственному тестированию (для снижения затрат на обслуживание). Исключение: научные методы могут иметь такие формы, как f (a (b (c (x), d (y))), a (e (x, z)), b (f (x, y, z), z)) где a, b, c, d, e и f - ужасно сложные выражения, но в остальном бесполезны вне этой единственной формулы. Некоторые функции (например, MD5) трудно инвертировать, поэтому может быть сложно (NP-Hard) выбрать параметры, которые будут полностью покрывать пространство поведения. Проще проверить a, b, c, d, e, f независимо. Делая их публичными или частно-ложными, они могут быть использованы повторно. Решение: сделайте их приватными, но протестируйте их.
Eponymous 30.08.2013 16:34:01
@ Одноименный, я немного разорван этим. Во мне объектно-ориентированный пурист сказал бы, что вы должны использовать объектно-ориентированный подход, а не статические приватные методы, что позволяет вам тестировать через общедоступные методы экземпляра. Но опять же, в научных рамках память, скорее всего, будет проблемой, которая, как я полагаю, доказывает статический подход.
Erik Madsen 2.09.2013 09:38:09

Обычно юнит-тест предназначен для использования открытого интерфейса класса или юнита. Следовательно, частные методы - это детали реализации, которые вы не ожидаете явно протестировать.

125
29.12.2012 09:52:20
Это лучший ответ IMO, или, как обычно говорят, тестовое поведение, а не методы. Модульное тестирование не является заменой метрик исходного кода, инструментов статического анализа кода и обзоров кода. Если частные методы настолько сложны, что им нужно разделить тесты, то, вероятно, их необходимо реорганизовать, а не создавать больше тестов.
Dan Haynes 17.05.2013 14:38:52
так что не пишите приватные методы, просто создайте 10 других маленьких классов?
razor 19.05.2015 16:42:04
Нет, это в основном означает, что вы можете проверить функциональность закрытых методов, используя открытый метод, который их вызывает.
Akshat Sharda 12.02.2020 14:53:03

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

58
29.08.2008 16:15:30
Истинный факт Проблема в том, что реализация более сложна, например, если один открытый метод вызывает несколько частных методов. Какой из них потерпел неудачу? Или, если это сложный частный метод, который нельзя
Z. Khullah 9.05.2018 18:11:05
Вы уже упоминали, почему закрытый метод должен быть протестирован. Вы сказали «тогда это может быть», поэтому вы не уверены. ИМО, следует ли тестировать метод, ортогонально его уровню доступа.
Wei Qiu 19.06.2018 03:04:14

Из этой статьи: Тестирование частных методов с помощью JUnit и SuiteRunner (Билл Веннерс), у вас в основном есть 4 варианта:

  • Не проверяйте частные методы.
  • Предоставьте доступ к пакету методов.
  • Используйте вложенный тестовый класс.
  • Используйте отражение.
205
21.09.2012 20:45:56
@JimmyT., Зависит от того, для кого предназначен «производственный код». Я бы назвал код, созданный для приложений, размещенных в VPN, целевыми пользователями которых являются системные администраторы, рабочим кодом.
Pacerier 21.08.2015 07:03:25
@Pacerier Что ты имеешь в виду?
Jimmy T. 21.08.2015 20:27:01
Пятый вариант, как упомянуто выше, тестирует открытый метод, который вызывает закрытый метод? Верный?
user2441441 12.07.2016 21:05:46
@LorenzoLerate Я боролся с этим, потому что я занимаюсь разработкой встраиваемых систем и хотел бы, чтобы мое программное обеспечение было как можно меньше. Ограничения по размеру и производительности - единственная причина, о которой я могу думать.
user2918461 20.09.2017 15:32:56
Мне очень нравится тест с использованием отражения: Здесь шаблон Method method = targetClass.getDeclaredMethod (methodName, argClasses); method.setAccessible (истина); return method.invoke (targetObject, argObjects);
Aguid 27.10.2017 21:13:24

Я склонен не проверять частные методы. Там лежит безумие. Лично я считаю, что вам следует тестировать только открытые интерфейсы (включая защищенные и внутренние методы).

14
29.08.2008 16:23:45

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

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

Это неправда. Вы, безусловно, можете, как уже упоминалось в ответе Джема Катиккаса .

6
14.12.2017 12:26:40
Вы не можете использовать отражение, чтобы получить приватные методы извне класса владельца, модификатор private также влияет на рефлексию. Вот хорошая статья на тему вопроса
juan 29.08.2008 16:34:15
@jmfsg В статье, на которую вы ссылаетесь, специально говорится: «Тестирование частных методов немного сложнее, но мы все еще можем сделать это с помощью System.Reflection». (Видимо, вам нужно ReflectionPermission, но обычно это не проблема.)
tc. 22.03.2013 20:03:36

Попробовав решение Cem Catikkas с использованием рефлексии для Java, я бы сказал, что это было более элегантное решение, чем я описал здесь. Однако, если вы ищете альтернативу использованию отражения и имеете доступ к тестируемому источнику, это все равно будет вариант.

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

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

Преимущества:

  • Может тестировать до мелкой гранулярности

Недостатки:

  • Тестовый код должен находиться в том же файле, что и исходный код, который может быть сложнее поддерживать
  • Аналогично с выходными файлами .class они должны оставаться в том же пакете, который объявлен в исходном коде.

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

Вот замысловатый пример того, как это будет работать:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

Внутренний класс будет скомпилирован в ClassToTest$StaticInnerTest.

См. Также: Java Совет 106: статические внутренние классы для удовольствия и выгоды

27
14.12.2017 12:22:32

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

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

Если вы хотите проверить сложные условия ошибки, возникающие из вспомогательного метода, вы можете пойти дальше. Извлеките интерфейс из вспомогательного класса, добавьте открытый метод получения и установки в исходный класс, чтобы внедрить вспомогательный класс (используемый через его интерфейс), а затем вставьте фиктивную версию вспомогательного класса в исходный класс, чтобы проверить, как исходный класс реагирует на исключения из помощника. Этот подход также полезен, если вы хотите протестировать исходный класс без тестирования вспомогательного класса.

22
13.01.2017 19:08:28

Если вы хотите протестировать приватные методы унаследованного приложения, в котором вы не можете изменить код, одним из вариантов для Java является jMockit , который позволит вам создавать макеты для объекта, даже когда они являются закрытыми для класса.

16
14.12.2017 12:23:33
Как часть библиотеки jmockit, у вас есть доступ к классу Deencapsulation, который упрощает тестирование частных методов: Deencapsulation.invoke(instance, "privateMethod", param1, param2);
Domenic D. 19.11.2013 04:22:57
Я использую этот подход все время. Очень полезно
MedicineMan 20.11.2017 05:38:36

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

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

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

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

319
19.05.2016 09:38:59
Вопрос был в том, как протестировать приватные методы. Вы говорите, что создадите новый класс для этого (и добавите намного больше сложности), и после предложите не создавать новый класс. Так как тестировать приватные методы?
Dainius 3.08.2012 11:40:40
@Dainius: я не предлагаю создавать новый класс исключительно, чтобы вы могли протестировать этот метод. Я полагаю, что написание тестов может помочь вам улучшить ваш дизайн: хороший дизайн легко проверить.
Jay Bazuzi 4.08.2012 21:15:14
Но вы согласны с тем, что хороший OOD будет предоставлять (обнародовать) только те методы, которые необходимы для корректной работы этого класса / объекта? все остальное должно быть private / protectec. Таким образом, в некоторых частных методах будет некоторая логика, и тестирование IMO этих методов только улучшит качество программного обеспечения. Конечно, я согласен с тем, что если какой-то фрагмент кода является сложным, его следует разделить на отдельные методы / классы.
Dainius 6.08.2012 06:53:33
@Danius: добавление нового класса в большинстве случаев уменьшает сложность. Просто измерить это. Тестируемость в некоторых случаях борется с OOD. Современный подход - это возможность тестирования.
AlexWien 1.07.2013 20:54:09
Это именно то, как использовать обратную связь от ваших тестов, чтобы вести и улучшать свой дизайн! Слушай свои тесты. если их трудно написать, это говорит вам кое-что важное о вашем коде!
pnschofield 2.12.2016 21:35:53

Как указывалось выше, хороший способ - проверить их через общедоступные интерфейсы.

Если вы сделаете это, будет полезно использовать инструмент покрытия кода (например, Эмму), чтобы увидеть, выполняются ли ваши частные методы из ваших тестов.

11
10.09.2008 07:48:42
Вы не должны косвенно проверять! Не только прикосновение через освещение; проверить, что ожидаемый результат достигнут!
AlexWien 1.07.2013 20:51:07

Если вы используете JUnit, взгляните на junit-addons . Он имеет возможность игнорировать модель безопасности Java и получать доступ к закрытым методам и атрибутам.

14
14.12.2017 12:24:27

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

Если они настолько велики, достаточно велики, что каждый из этих закрытых членов по сложности является «единичным», рассмотрите возможность рефакторинга таких закрытых членов из этого класса.

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

9
13.01.2017 19:12:04
Потому что часто конкретный фрагмент кода из открытого метода преобразуется во внутренний закрытый метод и на самом деле является критическим фрагментом логики, который вы могли ошибиться. Вы хотите проверить это независимо от публичного метода
oxbow_lakes 15.02.2009 17:33:07
Даже самый короткий код иногда без модульного теста не является правильным. Просто попробуйте рассчитать разницу между двумя географическими углами. 4 строки кода, и большинство не будет делать это правильно с первой попытки. Такие методы нуждаются в модульном тестировании, потому что они составляют основу надежного кода. (И такой полезный код тоже может быть публичным; менее защищенный
AlexWien 1.07.2013 20:48:57

Тестирование приватных методов нарушает инкапсуляцию вашего класса, потому что каждый раз, когда вы меняете внутреннюю реализацию, вы нарушаете клиентский код (в данном случае, тесты).

Так что не проверяйте частные методы.

18
29.12.2012 10:02:43
модульный тест и код src являются парой. Если вы измените src, возможно, вам придется сменить юнит-тест. В этом смысл теста джунит. Они должны гарантировать, что все работает как прежде. и хорошо, если они сломаются, если вы измените код.
AlexWien 1.07.2013 20:43:13
Не соглашайтесь, что модульный тест должен измениться, если код изменяется. Если вам приказано добавить функциональность в класс без изменения существующей функциональности класса, тогда существующие модульные тесты должны пройти даже после того, как вы изменили свой код. Как упоминает Питер, модульные тесты должны проверять интерфейс, а не то, как это делается внутри. В Test Driven Development модульные тесты создаются перед написанием кода, чтобы сосредоточиться на интерфейсе класса, а не на том, как он решается внутри.
Harald Coppoolse 9.11.2015 13:27:14

Как уже говорили другие ... не тестируйте частные методы напрямую. Вот несколько мыслей:

  1. Все методы должны быть небольшими и целенаправленными (легко тестировать, легко находить, что не так)
  2. Используйте инструменты покрытия кода. Мне нравится Cobertura (о, счастливый день, похоже, вышла новая версия!)

Запустите покрытие кода на модульных тестах. Если вы видите, что методы не полностью протестированы, добавьте тесты, чтобы увеличить охват. Стремитесь к 100% охвату кода, но понимайте, что вы, вероятно, не получите его.

25
13.01.2017 19:13:20
Вверх для покрытия кода. Независимо от того, какая логика в приватном методе, вы все равно вызываете эту логику через публичный метод. Инструмент покрытия кода может показать вам, какие части покрываются тестом, поэтому вы можете увидеть, тестировался ли ваш частный метод.
coolcfan 9.08.2012 02:20:11
Я видел классы, где единственный публичный метод - это main [], и у них всплывающий графический интерфейс плюс соединение базы данных и нескольких веб-серверов по всему миру. Легко сказать "не проверяй косвенно" ...
Audrius Meskauskas 12.12.2014 08:43:23

Вы можете отключить ограничения доступа к Java для отражения, так что private ничего не значит.

setAccessible(true)Вызов делает это.

Единственное ограничение - ClassLoader может запретить вам это делать.

Посмотрите Подрывание Защиты Доступа Java для Модульного тестирования (Росс Бертон) для способа сделать это в Java.

4
14.12.2017 12:27:51

В C # вы могли бы использовать System.Reflection, хотя в Java я не знаю. Хотя я все равно чувствую желание ответить на этот вопрос, так как, если вы «чувствуете, что вам нужно провести модульное тестирование частных методов», я думаю, что есть что-то еще, что не так ...

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

2
13.01.2017 19:15:16

Что если ваши тестовые классы находятся в том же пакете, что и класс, который должен быть протестирован?

Но в другом каталоге, конечно, srcи classesдля вашего исходного кода, test/srcи test/classesдля ваших тестовых классов. И пусть classesи test/classesбудет в вашем классе.

2
29.12.2012 10:05:53
тесты могут находиться в разных папках (например, src / test / java и код приложения в src / main / java), но пакет должен быть одинаковым.
razor 19.05.2015 16:40:53

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

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

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

286
14.12.2017 12:19:35
+1 к этому. На мой взгляд, это лучший ответ на вопрос. Тестируя частные методы, вы тестируете реализацию. Это противоречит цели модульного тестирования, которое заключается в проверке входных / выходных данных классового контракта. Тест должен знать только достаточно о реализации, чтобы смоделировать методы, которые он вызывает для своих зависимостей. Ничего больше. Если вы не можете изменить свою реализацию без необходимости менять тест, скорее всего, ваша стратегия тестирования плохая.
Colin M 8.07.2013 13:27:26
@Colin M Это не совсем то, о чем он спрашивает;) Пусть он сам решит, вы не знаете проект.
Aaron Marcus 2.04.2015 16:21:48
Не совсем правда. Может потребоваться много усилий, чтобы протестировать небольшую часть закрытого метода с помощью открытого метода, используя его. Открытый метод может потребовать значительной настройки, прежде чем вы достигнете линии, вызывающей ваш частный метод
ACV 30.11.2017 11:32:47
Я согласен. Вам следует проверить, выполнен ли контракт. Не стоит проверять, как это делается. Если контакт выполнен без достижения 100% покрытия кода (в частных методах), это может быть мертвый или бесполезный код.
wuppi 2.07.2019 07:43:30

Всего два примера, где я хотел бы протестировать приватный метод:

  1. Процедуры дешифрования - я бы не хотел, чтобы их кто-то видел, чтобы их можно было увидеть только для тестирования, иначе любой может использовать их для расшифровки. Но они свойственны коду, сложны и должны всегда работать (очевидное исключение - отражение, которое может использоваться для просмотра даже частных методов в большинстве случаев, когда SecurityManagerне настроено это предотвращать).
  2. Создание SDK для общественного потребления. Здесь публика принимает совершенно иное значение, поскольку это код, который может видеть весь мир (не только внутренний для моего приложения). Я помещаю код в приватные методы, если не хочу, чтобы пользователи SDK видели его - я не вижу в этом запаха кода, а просто как работает программирование SDK. Но, конечно же, мне все еще нужно протестировать свои частные методы, и именно там они действительно функционируют.

Я понимаю идею только тестирования "контракта". Но я не вижу, чтобы кто-то мог выступать за то, чтобы не тестировать код - ваш пробег может отличаться.

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

65
13.01.2017 19:24:04
Хотя вы никогда не должны делать метод публичным, просто чтобы проверить его, privateэто не единственная альтернатива. Отсутствие модификатора доступа package privateозначает, что вы можете выполнить его модульное тестирование, пока ваш модульный тест находится в одном пакете.
ngreen 10.04.2014 03:45:16
@ngreen это все правда, но не в этом вопрос. ОП спрашивает о тестировании частных методов. По умолчанию это не то же самое, что частное; как уже говорилось, вы можете легко увидеть метод доступа по умолчанию из класса, просто объявив этот класс в том же пакете. При частном доступе вам требуется рефлексия, а это совершенно другая игра в мяч.
Richard Le Mesurier 10.04.2014 10:06:33
Я комментировал ваш ответ, в частности пункт 1, а не ОП. Нет необходимости делать метод приватным только потому, что вы не хотите, чтобы он был публичным.
ngreen 10.04.2014 16:30:39
@ngreen true thx - мне было лень со словом «публика». Я обновил ответ, чтобы включить общедоступный, защищенный, дефолтный (и упомянуть о рефлексии). Суть, которую я пытался подчеркнуть, заключается в том, что у некоторого кода есть веские основания для секретности, однако это не должно помешать нам его протестировать.
Richard Le Mesurier 10.04.2014 16:46:39
Спасибо за реальные примеры для всех. Большинство ответов хороши, но с теоретической точки зрения. В реальном мире нам нужно скрыть реализацию от контракта, и нам все еще нужно протестировать ее. Читая все это, я думаю, что, возможно, это должен быть совершенно новый уровень тестирования, с другим названием
Z. Khullah 9.05.2018 18:00:40

Для тестирования унаследованного кода с большими и причудливыми классами часто очень полезно иметь возможность протестировать один приватный (или публичный) метод, который я пишу прямо сейчас .

Я использую пакет junitx.util.PrivateAccessor для Java. Много полезных однострочников для доступа к приватным методам и приватным полям.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);
33
14.12.2017 12:20:38
Обязательно загрузите весь пакет JUnit-addons ( sourceforge.net/projects/junit-addons ), а не проект SourceAgeed, рекомендованный Forge PrivateAccessor.
skia.heliou 15.01.2015 13:12:59
И убедитесь, что, когда вы используете в Classкачестве первого параметра в этих методах, что вы обращаетесь только к staticчленам.
skia.heliou 20.01.2015 19:40:28

Ответ со страницы часто задаваемых вопросов JUnit.org :

Но если ты должен ...

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

Если вы используете JDK 1.6 или выше и аннотируете свои тесты с помощью @Test, вы можете использовать Dp4j для добавления отражения в ваши методы тестирования. Подробнее о том, как его использовать, смотрите в этом тестовом скрипте .

PS Я основной участник Dp4j , спросите меня, если вам нужна помощь. :)

16
23.05.2017 11:55:10

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

Я минимизирую необходимость в этом и всегда документирую точные причины, чтобы избежать путаницы.

0
28.04.2011 15:01:47

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

Я не изменяю видимость метода, который хочу протестировать, и добавляю дополнительный метод. Вместо этого я добавляю дополнительный открытый метод для каждого частного метода, который я хочу протестировать. Я называю этот дополнительный метод Test-Portи обозначаю их префиксом t_. Test-PortЗатем этот метод просто обращается к соответствующему приватному методу.

Кроме того, я добавляю логический флаг к Test-Portметоду, чтобы решить, предоставить ли мне доступ к приватному методу через Test-Portметод извне. Этот флаг затем устанавливается глобально в статическом классе, где я размещаю, например, другие глобальные настройки для приложения. Таким образом, я могу включать и выключать доступ к закрытым методам в одном месте, например, в соответствующем модульном тесте.

3
13.01.2017 19:29:56

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

0
2.01.2012 20:12:54
Это взлом не реальное решение.
givanse 13.07.2012 14:49:07
@givanse Я не согласен ... это одна из причин, по которой тестирование Java-кода с использованием Groovy является настолько мощным.
Jeff Olson 7.05.2013 17:34:43

JML имеет синтаксис аннотации spec_public для комментариев, который позволяет вам указывать метод как public во время тестов:

private /*@ spec_public @*/ int methodName(){
...
}

Этот синтаксис обсуждается по адресу http://www.eecs.ucf.edu/~leavens/JML/jmlrefman/jmlrefman_2.html#SEC12 . Также существует программа, которая переводит спецификации JML в тесты JUnit. Я не уверен, насколько хорошо это работает или каковы его возможности, но в этом нет необходимости, поскольку JML сам по себе является жизнеспособной средой тестирования.

1
4.03.2013 00:07:43

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

Если у вас есть код с закрытыми методами, полями или конструкторами, вы можете использовать BoundBox . Это именно то, что вы ищете. Ниже приведен пример теста, который обращается к двум закрытым полям действия Android для его проверки:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox позволяет легко тестировать приватные / защищенные поля, методы и конструкторы. Вы даже можете получить доступ к вещам, которые скрыты по наследству. Действительно, BoundBox нарушает инкапсуляцию. Это даст вам доступ ко всему этому через рефлексию, НО все проверяется во время компиляции.

Он идеально подходит для тестирования некоторого устаревшего кода. Используйте это осторожно. ;)

https://github.com/stephanenicolas/boundbox

10
14.12.2017 12:25:37
Только что попробовал, BoundBox это простое и элегантное решение!
forhas 2.10.2013 14:12:14

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

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

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

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

25
13.01.2017 19:33:13
Хотя это и правда, это может привести к некоторым очень сложным тестам - лучше тестировать один метод за раз (модульное тестирование), а не целую группу из них. Не страшное предложение, но я думаю, что здесь есть лучшие ответы - это должно быть последним средством.
Bill K 30.09.2016 21:51:23

Вот моя общая функция для проверки приватных полей:

protected <F> F getPrivateField(String fieldName, Object obj)
    throws NoSuchFieldException, IllegalAccessException {
    Field field =
        obj.getClass().getDeclaredField(fieldName);

    field.setAccessible(true);
    return (F)field.get(obj);
}
11
13.01.2017 19:33:48