Открытый метод Unit Test, который вызывает закрытый метод и другие объекты в Java - PullRequest
0 голосов
/ 02 марта 2019

Я новичок в модульном тестировании и недавно попробовал свои силы в тестах JUnit и Mockito.

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

Как мне выполнить модульное тестирование метода.

Например, если у меня есть следующий код:

class ClassToTest {
    private OuterClass outerClass;
    public Boolean function() {
        outerClass = new OuterClass(20);
        return innerFunction(outerClass.getValue());
    }

    private Boolean innerFunction(int val) {
        if (val % 2 == 0)
            return true;
        return false;
    }
}

Я запутался, как бы я протестировал публичную функцию.

Ответы [ 3 ]

0 голосов
/ 02 марта 2019

Как правило, в случае с Mockito это потребует использования Dependency Injection, а затем вы будете внедрять макет OuterClass для теста.

Если вы действительно хотите протестировать это без добавления фреймворка Spring, я могу подумать о трех вариантах:

1) Сделать это интеграционным тестом и проверить реальные экземпляры всего

2) Измените ваш код так, чтобы OuterClass создавался с помощью переданного объекта Object из установщика или конструктора, а затем передайте макет для вашего теста

3) Измените private OuterClass outerClass; на protected OuterClass outerClass; и убедитесь, что структура вашего пакета тестов совпадает с фактической структурой пакета кода, и тогда вы можете выполнить outerClass = Mockito.mock(OuterClass); в настройках теста.

0 голосов
/ 03 марта 2019

Вы начинаете юнит-тестирование с непосредственного перехода к некоторым нетривиальным вопросам.

Вопрос 1: Как обращаться с деталями реализации / частными функциями? Ответ: Юнит-тестированиепоиск ошибок в вашем коде, и это одна из основных задач модульного тестирования (и большинства других видов тестирования).Другая основная цель - предотвратить появление ошибок, выполняя роль регрессионных тестов при изменении программного обеспечения.Ошибки есть в реализации - разные реализации идут с разными ошибками.Поэтому обязательно проверьте детали реализации.Одним из важных инструментов для поддержки здесь является анализ покрытия, который показывает, какие части кода реализации были достигнуты вашими тестами.

Вы можете даже протестировать аспекты, выходящие за рамки контракта функции: a) Отрицательные тесты - это тестыкоторые намеренно проверяют поведение на наличие неверных / неуказанных входных данных и важны для обеспечения безопасности системы.Поскольку даже при наличии неверного ввода система не должна быть взломана, например, из-за чтения или записи за пределы памяти.Это, однако, вероятно, не относится к вашему примеру, потому что ваш метод, скорее всего, предназначен для реализации «полной функции», а не «частичной функции».b) Тесты деталей реализации (если они доступны) могут быть даже выполнены за пределами того, что требуется для текущей реализации.Это может быть сделано для предотвращения ошибок в будущих изменениях компонента, таких как расширения API.

Однако существуют и вторичные цели модульного тестирования.Один из них заключается в том, чтобы избежать ненужных сбоев ваших тестов при изменении деталей реализации.Один из подходов к достижению вторичной цели состоит в тестировании деталей реализации через общедоступный API.Таким образом, некоторые виды перепроектирования деталей реализации не будут нарушать ваши тесты: переименование, разбиение или объединение частных функций не повлияет на тесты.Однако переключение на другой алгоритм, вероятно, потребует от вас переосмысления ваших тестов: тесты для итеративной / рекурсивной реализации функции Фибоначчи будут выглядеть иначе, чем для реализации, использующей выражение закрытой формы из Moivre / Binet, илидля реализации таблицы поиска.

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

Вопрос 2: Как поступитьс зависимостями от других частей программного обеспечения? Модульное тестирование фокусируется на поиске ошибок в небольших изолированных фрагментах кода.Когда эти фрагменты кода имеют зависимости от других частей кода, это может негативно повлиять на вашу способность правильно их тестировать.Но действительно ли это так, зависит от фактической зависимости.Например, если в вашем коде используется функция Math.sin(), это также зависимость от другой части кода, но такая зависимость, как правило, не вредит вашей способности правильно тестировать код.

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

Если все эти критерии не выполнены (как это обычно бывает с функцией Math.sin()), вы обычно можете просто жить с другимкомпоненты, являющиеся частью ваших испытаний.Однако вы должны помнить, что в своих модульных тестах вы по-прежнему сосредотачиваетесь на ошибках в своем коде и не начинаете писать тесты, которые фактически тестируют другие компоненты: имейте в виду, что другие компоненты имеют свои собственные тесты.

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

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

0 голосов
/ 02 марта 2019

Неважно, как метод реализован;этот метод должен иметь контракт, которому он подчиняется, и , что - это то, что вы проверяете с помощью теста.В этом примере function() должен вернуть true, если значение outerClass четное.Один из способов сделать это - внедрить (передать в конструктор ClassToTest) экземпляр outerClass, чтобы вы могли контролировать значение при тестировании:

@Test
public void trueWhenEven() {
    var outer = new OuterClass(2);
    var ctt = new ClassToTest(outer);
    assertTrue(ctt.function());
}

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

...