Java Language
Тестирование устройства
Поиск…
Вступление
замечания
Структуры тестовых модулей
Для модульного тестирования в Java существует множество возможностей. Самым популярным вариантом является JUnit. Он документируется следующим образом:
JUnit4 - Предлагаемый тег для функций JUnit4; еще не реализованы .
Существуют другие платформы тестирования модулей и доступны документация:
Инструменты для тестирования единиц
Для модульного тестирования используется несколько других инструментов:
Мокито - Издевательская структура; позволяет копировать объекты. Полезно для имитации ожидаемого поведения внешнего устройства в рамках теста данного устройства, чтобы не связывать поведение внешнего устройства с тестами данного устройства.
JBehave - BDD Framework. Позволяет связать тесты с пользовательским поведением (разрешая проверку требований / сценариев). Отсутствие ярлыков документов на момент написания; вот внешняя ссылка .
Что такое Unit Testing?
Это немного грунт. В основном это связано с тем, что документация вынуждена иметь пример, даже если он предназначен как статья-заглушка. Если вы уже знаете основы модульного тестирования, не стесняйтесь переходить к замечаниям, где упоминаются конкретные рамки.
Модульное тестирование - это обеспечение того, что данный модуль ведет себя так, как ожидалось. В крупномасштабных приложениях обеспечение надлежащего выполнения модулей в вакууме является неотъемлемой частью обеспечения верности приложения.
Рассмотрим следующий (тривиальный) псевдо-пример:
public class Example {
public static void main (String args[]) {
new Example();
}
// Application-level test.
public Example() {
Consumer c = new Consumer();
System.out.println("VALUE = " + c.getVal());
}
// Your Module.
class Consumer {
private Capitalizer c;
public Consumer() {
c = new Capitalizer();
}
public String getVal() {
return c.getVal();
}
}
// Another team's module.
class Capitalizer {
private DataReader dr;
public Capitalizer() {
dr = new DataReader();
}
public String getVal() {
return dr.readVal().toUpperCase();
}
}
// Another team's module.
class DataReader {
public String readVal() {
// Refers to a file somewhere in your application deployment, or
// perhaps retrieved over a deployment-specific network.
File f;
String s = "data";
// ... Read data from f into s ...
return s;
}
}
}
Итак, этот пример тривиален; DataReader
получает данные из файла, передает его в « Capitalizer
, который преобразует все символы в верхний регистр, который затем передается Consumer
. Но DataReader
сильно связан с нашей прикладной средой, поэтому мы откладываем тестирование этой цепочки, пока не готовы к развертыванию тестовой версии.
Теперь предположим, что где-то по пути в релизе по неизвестным причинам метод getVal()
в Capitalizer
изменился с возврата строки toUpperCase()
строку toLowerCase()
:
// Another team's module.
class Capitalizer {
...
public String getVal() {
return dr.readVal().toLowerCase();
}
}
Ясно, что это нарушает ожидаемое поведение. Но из-за трудных процессов, связанных с выполнением DataReader
, мы не заметим этого до нашего следующего тестового развертывания. Таким образом, дни / недели / месяцы проходят с этой ошибкой, сидящей в нашей системе, а затем менеджер продукта видит это и мгновенно обращается к вам, руководителю группы, связанному с Consumer
. «Почему это происходит? Что вы, ребята, изменили?» Очевидно, ты не знаешь. Вы понятия не имеете, что происходит. Вы не изменили код, который должен касаться этого; почему это внезапно нарушено?
В конце концов, после обсуждения между командами и совместной работой проблема прослеживается, и проблема решена. Но он задает вопрос; как это могло быть предотвращено?
Есть две очевидные вещи:
Тесты должны быть автоматизированы
Наша уверенность в ручном тестировании позволяет этой ошибке проходить незаметно слишком долго. Нам нужен способ автоматизировать процесс, при котором ошибки вводятся мгновенно . Не через 5 недель. Не через 5 дней. Не через 5 минут. Прямо сейчас.
Вы должны оценить, что в этом примере я изложил одну очень тривиальную ошибку, которая была введена и незаметна. В промышленном применении с постоянно обновляющимися десятками модулей они могут ползти повсюду. Вы исправляете что-то с помощью одного модуля, только чтобы понять, что само поведение, которое вы «зафиксировали», каким-то образом опиралось на другое (внутреннее или внешнее).
Без строгой проверки все будет проникать в систему. Возможно, что, если пренебречь достаточно далеко, это приведет к такой дополнительной работе, которая поможет исправить изменения (а затем исправить эти исправления и т. Д.), Что продукт действительно увеличится в оставшейся работе, так как в нее будут включены усилия. Вы не хотите быть в такой ситуации.
Тесты должны быть мелкозернистыми
Вторая проблема, отмеченная в нашем примере выше, - это время, затраченное на прослеживание ошибки. Менеджер продукта пинговал вас, когда тестеры заметили это, вы исследовали и обнаружили, что « Capitalizer
возвращал, казалось бы, плохие данные, вы пинали команду « Capitalizer
» вашими результатами, они исследовали и т. Д. И т. Д. И т. Д.
То же самое, что я сделал выше о количестве и сложности этого тривиального примера, здесь. Очевидно, что любой разумно хорошо разбирающийся в Java может быстро найти введенную проблему. Но часто и гораздо труднее отслеживать и передавать проблемы. Возможно, команда Capitalizer
предоставила вам JAR без источника. Возможно, они расположены на другой стороне мира, а часы общения очень ограничены (возможно, по электронной почте, которые отправляются один раз в день). Это может привести к ошибкам, требующим недель или больше для отслеживания (и, опять же, для данной версии может быть несколько).
Для того , чтобы смягчать против этого, мы хотим , тщательное тестирование на максимально тонкий уровне , насколько это возможно (вы также хотите крупнозернистое тестирование , чтобы обеспечить модули взаимодействуют должным образом, но это не наш фокус здесь). Мы хотим строго указать, как работают все внешние функции (как минимум), и тесты для этой функциональности.
Введите модульное тестирование
Представьте себе, если бы у нас был тест, в частности, чтобы метод getVal()
Capitalizer
возвращал getVal()
строку для данной входной строки. Кроме того, представьте, что тест был выполнен до того, как мы даже совершили какой-либо код. Ошибка, введенная в систему (то есть toUpperCase()
заменяется на toLowerCase()
), не вызовет проблем, потому что ошибка никогда не будет введена в систему. Мы поймаем его в тесте, разработчик (надеюсь) осознает свою ошибку, и будет найдено альтернативное решение о том, как внедрить их предполагаемый эффект.
Здесь приводятся некоторые упущения в отношении того, как выполнять эти тесты, но они описаны в документации по структуре (см. Примечания). Надеюсь, это служит примером того, почему модульное тестирование важно.