Аннотации, чтобы сделать приватный метод общедоступным только для тестовых классов

У кого есть решение для этой общей потребности.

У меня есть класс в моем приложении.

некоторые методы являются общедоступными, поскольку они являются частью api, и некоторые частные, поскольку они для внутреннего использования делают внутренний поток более читабельным

теперь, скажем, я хочу написать unit test или больше как тест интеграции, который будет расположен в другом пакете, который будет разрешен для вызова этого метода, НО, я хочу, чтобы обычный вызов этого метода не будет разрешено, если вы попытаетесь вызвать его из классов самого приложения

Итак, я думал о чем-то вроде этого

public class MyClass {

   public void somePublicMethod() {
    ....
   }

   @PublicForTests
   private void somePrivateMethod() {
    ....
   }
}

В аннотации выше будет отмечен частный метод как "общедоступный для тестов", это означает, что компиляция и время выполнения будут разрешены для любого класса, который находится под тестом..., а компиляция и\или время выполнения не удастся для любого класса, который не находится под тестовым пакетом.

любые мысли? есть ли такая аннотация? есть ли лучший способ сделать это?

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

Ответ 1

Общий способ заключается в том, чтобы защитить частный метод или пакет-частный и поместить unit test для этого метода в тот же пакет, что и тестируемый класс. Guava имеет @VisibleForTesting аннотацию, но только для целей документации.

Ответ 2

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

JUnit Doc говорит:

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

Ответ 3

Рассмотрим использование интерфейсов для раскрытия методов API, используя фабрики или DI для публикации объектов, чтобы потребители знали их только по интерфейсу. Интерфейс описывает опубликованный API. Таким образом, вы можете сделать все, что хотите публиковать на объектах реализации, а потребители из них видят только те методы, которые открываются через интерфейс.

Ответ 4

dp4j имеет то, что вам нужно. По существу, все, что вам нужно сделать, это добавить dp4j в свой путь к классам и всякий раз, когда метод, аннотированный с помощью @Test (аннотация JUnit), вызывает метод, который он будет работать, (dp4j будет вводить требуемое отражение во время компиляции). Вы также можете использовать аннотацию dp4j @TestPrivates, чтобы быть более явным.

Если вы настаиваете на аннотации ваших личных методов, вы можете использовать аннотацию Google @VisibleForTesting.

Ответ 5

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

Ответ 6

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

Ответ 7

Я не знаю какой-либо такой аннотации, однако следующее может иметь значение: unit testing private methods
или следующее: JMockit

Ответ 8

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

Существует два общих подхода к этому

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

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

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

Ответ 9

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

Для класса, подобного

public class Outer {
    private static class Inner {
        private int foo() {return 2;}
    }
}

Он предоставляет такой синтаксис, как:

Outer outer = new Outer();
Object inner = BoundBoxOfOuter.boundBox_new_Inner();
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo();

Единственное, что вам нужно сделать, чтобы создать класс BoundBox, это написать @BoundBox(boundClass=Outer.class), а класс BoundBoxOfOuter будет мгновенно сгенерирован.

Ответ 10

Хорошо, так что у нас есть две вещи, которые смешиваются. Во-первых, когда вам нужно отметить что-то, что нужно использовать только на тесте, которое я согласен с @JB Nizet, использование аннотации guava было бы хорошим.

Другое дело - проверить частные методы. Почему вы должны тестировать частные методы извне? Я имею в виду... Вы должны быть способны проверить объект своими общедоступными методами, а в конце - на его поведение. По крайней мере, что мы делаем и пытаемся научить младших разработчиков, которые всегда стараются проверять частные методы (как хорошую практику).

Ответ 11

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

Вам следует только следить за тестированием результата исключения из метода. Например: если u ожидает исключение IllegalArgumentException, но вместо этого вы получите "null" (класс: java.lang.reflect.InvocationTargetException).
Я предлагаю использовать эту концепцию > powermock framework для этих ситуаций, но я еще не тестировал ее, поэтому не знаю, что именно она может сделать, Хотя я использовал фреймворк Mockito, на котором он основан, и thats хорошая структура тоже (но я думаю, что не решает проблему исключения частного метода).

Это отличная идея, хотя есть аннотация @PublicForTests.

Ура!