Рис. 14.1
Каталоги с тестами в Android Studio
В первой папке будет находиться весь исходный код. В папке с меткой
(test) – модульные и интеграционные тесты. А в последней папке с меткой (an
-
droidTest) – тесты пользовательского интерфейса на основе Espresso, но о них
мы не будем рассказывать в этой главе.
Независимо от выбора языка для проекта, Java или Kotlin, дерево каталогов
проекта будет иметь одну и ту же структуру. Если потом вы добавите файлы
противоположного типа (например, в проект на Kotlin добавите файлы на Java
или наоборот), то обнаружите, что для каждого языка будет создан свой комп-
лект каталогов – по одному для исходного кода, модульных и интеграционных
тестов и тестов пользовательского интерфейса.
Как писать и запускать модульные тесты
Все тесты, основанные на JUnit и Robolectric, помещаются в каталог с меткой
(test), который далее мы будем называть просто «каталогом с тестами».
Открыв эту папку, вы обнаружите в ней готовый пример тестового класса
с именем ExampleUnitTest. Он импортирует базовые статические методы
as
sert
из JUnit и может включать какие-то элементарные проверки, например:
218
Тестирование
Java
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
Kotlin
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
Это реализация простейшего модульного теста. Каждый модульный тест
проверяет одну функциональную единицу кода. В предыдущем примере мало
пользы, так как все проверяемые операторы находятся внутри самого теста,
поэтому давайте рассмотрим немного более полезный пример:
Java
public class Calculator {
public static add(int a, int b) {
return a + b;
}
}
Kotlin
fun add(a: Int, b: Int): Int {
return a + b
}
Протестировать этот простой класс можно с помощью следующего модуль
-
ного теста:
Java
public class CalculatorTest {
@Test
public void add_returnsCorrectValue_forPositiveValues() {
int expected = 4;
int actual = Calculator.add(2, 2);
assertEquals(expected, actual);
}
}
Kotlin
class AddTest {
@Test
fun add_returnsCorrectValue_forPositiveValues() {
val expected = 4
Android
219
val actual = add(2, 2)
assertEquals(expected, actual)
}
}
Обратите внимание, что методы
assert
принимают «фактическое» (
actual
)
значение, полученное логикой класса, и «ожидаемое» (
expected
), которое долж
-
на сгенерировать эта логика. Они сравнивают полученные значения, и если те
не совпадают (или не соответствуют результату, предполагаемому конкретны
-
ми версиями метода
assert
, такими как
assertTrue
или
assertFalse
), то просто
генерируют исключения, которые затем перехватываются фреймворком тес-
тирования и помогают определить, какие тесты пройдены успешно, а какие
потерпели неудачу.
Модульные тесты для процедурного кода, всегда возвращающего одинако
-
вые результаты в ответ на одни и те же входные данные, почти всегда уместны
и полезны. В случае с окружениями, основанными на состоянии (например,
в объектно-ориентированном программировании на Java и Kotlin), дело может
обстоять несколько сложнее.
Интегрируя свой код в платформу, такую как AOSP, разработчик полагает
-
ся на определенные возможности, классы и значения. Соответственно, тесты,
проверяющие этот код, могут стать более сложными, это особенно верно, ког
-
да дело доходит, например, до компонентов
Ac ti vi ty
или событий жизненно
-
го цикла. Именно по этой причине была создана библиотека Robolectric – она
обеспечивает возможность организации взаимодействий с подобными меха
-
низмами инфраструктуры простым и понятным способом.
Обратите внимание, что в настоящее время целью развития библиотеки
Robolectric является ее включение в общий фреймворк Android Test, и на по
-
следней конференции Google I/O, прошедшей перед публикацией этой книги,
многие выступавшие отмечали, что поддержку Android в Robolectric скоро за
-
менит идентичная поддержка из новых пакетов AndroidX. То есть привлече
-
ние AndroidX для тестирования имеет определенную ценность. Использова
-
ние синтаксиса Espresso для реализации локальных и инструментированных
тестов пользовательского интерфейса может дать огромные преимущества
любой команде, но в то же время некоторые нетривиальные ошибки, обнару
-
женные нами за год, помешали нашей команде полностью мигрировать на эту
библиотеку.
Когда тесты должны интегрироваться с другим кодом, особенно с малоиз
-
вестными наборами инструментов, такими как средства рисования пикселей
на экране в Android, вы действительно можете столкнуться с существенными
ограничениями. При написании тестов учитывайте целесообразность трудоза
-
трат. Вам часто будет встречаться термин «охват»; обычно под ним понимается
доля кода, охваченного тестированием, но на самом деле существует множест-
во самых разных способов оценки охвата – кто-то подсчитывает количество
строк со ссылками, кто-то подсчитывает инструкции и даже ветви условных
операторов. Если требуется обеспечить 100%-ный охват для нового продукта,
вам (и вашей команде), возможно, придется определить наилучший и наибо
-
лее практичный подход к тестированию. В зависимости от используемого у вас
определения термина «охват» может оказаться невозможным достичь 100 %
220
Тестирование
охвата. В предыдущем тесте, проверяющем работу метода
Calculator.add
, мож
-
но предположить, что достаточно одного (или нескольких) подобного теста,
и едва ли кто-то предложит проверить все возможные комбинации двух целых
чисел,
но
у вас может появиться желание проверить, что произойдет при сло
-
жении двух целых чисел, сумма которых превышает максимальное целочис
-
ленное значение в вашей системе, а также при сложении двух отрицательных
или нулевых значений. Как уже говорилось, вы и ваша команда должны опре
-
делить область тестирования, требования, охват и приемы, и они могут сильно
отличаться в разных организациях и даже в разных подразделениях внутри
организации.
Do'stlaringiz bilan baham: |