Как мне проверить приватную функцию или класс, который имеет закрытые методы, поля или внутренние классы? - PullRequest
2484 голосов
/ 29 августа 2008

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

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

Ответы [ 48 ]

26 голосов
/ 02 сентября 2008

Попробовав решение 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: Статические внутренние классы для удовольствия и прибыли

23 голосов
/ 14 февраля 2009

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

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

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

23 голосов
/ 03 декабря 2013

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

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

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

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

23 голосов
/ 24 июня 2015

В Spring Framework вы можете тестировать частные методы, используя этот метод:

ReflectionTestUtils.invokeMethod()

Например:

ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");
22 голосов
/ 11 ноября 2014

При использовании Spring ReflectionTestUtils предоставляет некоторые удобные инструменты, которые помогут вам с минимальными усилиями. Например, чтобы настроить макет для закрытого участника без необходимости добавлять нежелательный общедоступный установщик:

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);
21 голосов
/ 05 сентября 2008

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

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

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

16 голосов
/ 10 октября 2008

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

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

15 голосов
/ 09 сентября 2008

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

15 голосов
/ 22 февраля 2011

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

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

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

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

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

13 голосов
/ 29 августа 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...