В компании «Agoda» мы уделяем много внимания различным видам тестирования нашего кода. Это помогает нам гарантировать его стабильность и находить возможные проблемы продукта на раннем этапе.
В данный момент, тестирование пользовательского интерфейса на Android для нас является небольшим персональным филиалом ада. Google предоставляет нам Espresso вместе с несколькими расширениями, UI автоматор и так далее. И хоть инструменты отлично справляются c возложенной на них задачей, делают они это не очень красиво. Когда вам нужно протестировать кейс, отличающийся от простого клика по кнопке, ваш тестовый код превращается в месиво, сложно поддающееся чтению. Просто взгляните:
@Test
public void espressoTest() {
onView(allOf(allOf(withId(R.id.label_bf_hotelname),
isDescendantOfA(withId(R.id.custom_view_trip_review))),
isDescendantOfA(withId(R.id.contentView))))
.check(matches(withEffectiveVisibility(View.VISIBLE)));
}
Для меня этот код выглядит малочитаемым. Очень сложно поддерживать работу более чем 1000 UI тестов нашего Android приложения с подобным синтаксисом. Но Google объявила официальную поддержду языка Kotlin как языка для Android разработки на конференции Google I/O 2017. Тогда то мы и подумали: «А ведь мы можем попробовать мигрировать наши тесты на Kotlin!»
Но просто трансляция кода из Java в Kotlin не решает нашу проблему с читаемостью тестов, так как мы все еще зависим от Espresso. К счастью, Kotlin предоставляет нам множество инструментов для создания DSL. Имея это ввиду, мы представили как наши UI тесты должны выглядеть на Kotlin'е. Мы хотели, чтобы тест выше выглядел вот так:
@Test
fun espressoTest() {
screen { hotelName { isVisible() } }
}
Выглядит здорово, вы так не считаете? Гораздо более читаемый и с легкостью понимаемый код, чем при использовании Espresso. И в большинстве ситуаций более компактный. Удалось ли нам добиться такого синтаксиса? Еще как!
Встречайте Kakao — простой Kotlin DSL для Android UI тестов с Espresso. Kakao предоставляет удобный синтаксис для создания UI тестов с помощью абстракции ваших Activity/Fragment или View через класс Screen.
open class TestActivityScreen: Screen<TestActivityScreen>() {
val content: KView = KView { withId(R.id.content) }
val map: KView = KView { withId(R.id.map) }
val button: KButton = KButton { withId(R.id.button) }
val textViewLarge: KTextView = KTextView {
withId(R.id.text_view_large)
}
val textViewSmall: KTextView = KTextView {
withId(R.id.text_view_small)
}
}
Чтобы начать использовать Kakao, вы должны включить поддержку Kotlin'а в вашем проекте. Вы можете найти всю необходимую для этого информацию на developer.android.com. Затем вам необходимо объявить вашу иерархию элементов интерфейса, используя классы, которые предоставляет библиотека. Все эти классы (KView, KTextView, KButton) — пустые классы, которые наследуют логику интерфейсов: действий (Actions) и утверждений (Assertions). Также библиотека предоставляет вспомогательные классы для создания matcher'ов в стиле DSL. Один из этих классов называется ViewBuilder и используется в конструкторах всех наследников KView.
class KTextView : KBaseView<KTextView>, TextViewAssertions {
constructor(function: ViewBuilder.() -> Unit): super(function)
constructor(parent: Matcher<View>, function: ViewBuilder.() -> Unit): super(parent, function)
constructor(parent: DataInteraction, function: ViewBuilder.() -> Unit): super(parent, function)
}
После декларации иерархии пользовательского интерфейса, вы можете получить прямой доступ к объекту Screen и всем находящимся в нем объектам KView при помощи оператора invoke и совершать различные действия или утверждения в каскадном стиле:
@RunWith(AndroidJUnit4::class)
class TestActivityTest {
@Rule
@JvmField
val rule = ActivityTestRule(TestActivity::class.java)
val screen = TestActivityScreen()
@Test
fun test() {
screen {
content { isVisible() }
textViewLarge {
click()
isVisible()
hasAnyText()
}
textViewSmall {
isVisible()
hasAnyText()
}
map {
click()
hasAnyTag("test_tag", "non_test_tag")
}
button { hasText("BUTTON") }
}
}
}
Мы уже перевели большинство наших тестов на использование Kakao и очень довольны результатом. Библиотека также поддерживает более сложные конструкции, такие как RecyclerView, ListView, WebView и так далее. Также она обладает удобным подходом к кастомизации, позволяя легко создавать собственные имплементации KView с различным набором действий и утверждений, вложенными элементами и логикой.
Мы решили выпустить этот инструмент публично, чтобы другие разработчики могли начать писать UI тесты на Kotlin'е без нужды придерживаться синтаксиса Espresso, который на наш взгляд устарел.
Вы можете подключить Kakao в свой проект, просто добавив эту строчку в Ваш build.gradle:
androidTestCompile 'com.agoda.kakao:kakao:1.0.0'
Присоединяйтесь к нам на GitHub, оцените Kakao и давайте вместе сделаем UI тестирование снова великим! Счастливого тестирования!
Автор: Alviere