Конфигуратор Kaspresso
Класс Kaspresso — это единственная точка для установки параметров Kaspresso.
Разработчик может настроить Kaspresso, установив Kaspresso.Builder
в конструкторах TestCase
, BaseTestCase
, TestCaseRule
, BaseTestCaseRule
.
Пример:
class SomeTest : TestCase(
kaspressoBuilder = Kaspresso.Builder.simple {
beforeEachTest {
testLogger.i("The beginning")
}
afterEachTest {
testLogger.i("The end")
}
}
) {
// ваш тест
}
Структура
Конфигурация Kaspresso содержит:
Kakao clicks
Kaspresso предоставляет возможность переопределить кастомные клики Espresso. Kakao библиотека предоставляет набор подготовленных имплементаций кликов, которые улучшают стабильность тестов на девайсах, находящихся под большой нагрузкой.
Все детали о проблеме и решениях описано в Kakao документации.
Пример, как заиспользовать кастомные клики в вашем тесте, представлен в CustomClickTest.
class ClickTest : TestCase(
kaspressoBuilder = Kaspresso.Builder.simple(
customize = {
clickParams = ClickParams.kakaoVisual()
}
)
) {
// your test
}
Kaspresso предоставляет следующие подготовленные опции для кастомизации кликов:
1. ClickParams.kakaoVisual()' - Kakao clicks с визуализацией.
2.
ClickParams.kakao()' - Kakao clicks.
3. `ClickParams.default()' - Espresso clicks. Используются по умолчанию.
Логгеры
Kaspresso предоставляет два вида логгеров: libLogger
и testLogger
.
libLogger
- внутренний логгер Kaspresso
testLogger
- логгер, который доступен разработчикам в тестах.
Последний доступен через свойство testLogger
в тестовых разделах (before, after, init, transform, run
) в тестовом DSL (из класса TestContext
).
Кроме того, он доступен при настройке Kaspresso.Builder
, если вы хотите добавить его, например, в свои пользовательские перехватчики.
Перехватчики Kaspresso на базе перехватчиков Kakao/Kautomator.
Эти перехватчики были введены для упрощения и единообразия использования перехватчиков Kakao и перехватчиков Kautomator.
Важный момент о смешении перехватчиков Kaspresso и перехватчиков Kakao/Kautomator.
Перехватчики Kaspresso не будут работать, если вы установите свои собственные перехватчики Kakao, вызвав метод Kakao.intercept
в тесте, или установите свои пользовательские перехватчики Kautomator, вызвав Kautomator.intercept
в тесте.
Если вы установите свои пользовательские перехватчики Kakao для конкретного экрана или KView и установите для аргумента isOverride значение true, то перехватчики Kaspresso не будут работать для конкретного экрана или KView
. То же самое верно и для Kautomator, где разработчик взаимодействует с UiScreen
и UiBaseView
.
Перехватчики Kaspresso можно разделить на два типа:
Behavior Interceptors
- перехватывают вызовыViewInteraction
,DataInteraction
,WebInteraction
,UiObjectInteraction
,UiDeviceInteraction
и выполняют свою логику.
Внимание, мы собираемся рассмотреть некоторые важные примечания оперехватчиках поведения
в конце этого документа.Watcher Interceptors
- перехватывают вызовыViewAction
,ViewAssertion
,Atom
,WebAssertion
,UiObjectAssertion
,UiObjectAction
,UiDeviceAssertion
,UiDeviceAction
и еще кое-что.
Расширим упомянутые типы перехватчиков Kaspresso:
Behavior Interceptors
viewBehaviorInterceptors
- перехватывают вызовыViewInteraction#perform
иViewInteraction#check
dataBehaviorInterceptors
- перехватывают вызовыDataInteraction#check
webBehaviorInterceptors
- перехватывают вызовыWeb.WebInteraction<R>#perform
иWeb.WebInteraction<R>#check
objectBehaviorInterceptors
- перехватывают вызовыUiObjectInteraction#perform
иUiObjectInteraction#check
deviceBehaviorInterceptors
- перехватывают вызовыUiDeviceInteraction#perform
иUiDeviceInteraction#check
Watcher Interceptors
viewActionWatcherInterceptors
– выполняют какие-то действия до того, как будет вызванandroid.support.test.espresso.ViewAction.perform
viewAssertionWatcherInterceptors
– выполняют какие-то действия до того, как будет вызванandroid.support.test.espresso.ViewAssertion.check
atomWatcherInterceptors
– выполняют какие-то действия до того, как будет вызванandroid.support.test.espresso.web.model.Atom.transform
webAssertionWatcherInterceptors
— выполняют какие-то действия до того, как будет вызванandroid.support.test.espresso.web.assertion.WebAssertion.checkResult
objectWatcherInterceptors
- выполняют какие-то действия до того, как будет вызванUiObjectInteraction.perform
илиUiObjectInteraction.check
deviceWatcherInterceptors
- выполняют какие-то действия до того, как будет вызванUiDeviceInteraction.perform
илиUiDeviceInteraction.check
Пожалуйста, помните! Перехватчики поведения и наблюдателя работают под капотом в каждом действии (actions) и утверждении (assertions) каждого графического элемента (View) Kakao и Kautomator по умолчанию в Kaspresso.
Специальные перехватчики Kaspresso
Эти перехватчики не основаны на какой-то lib. Краткое описание:
stepWatcherInterceptors
- перехватчик действий жизненного цикла SteptestRunWatcherInterceptors
- перехватчик всех действий жизненного цикла Test.
Как вы заметили, эти перехватчики также являются частью Watcher Interceptors.
BuildStepReportWatcherInterceptor
Этот watcher interceptor
по умолчанию включен в Kaspresso configurator
для сбора информации о шагах ваших тестов для дальнейшей обработки в оркестраторе тестов.
Этот перехватчик основан на AllureReportWriter
(подробнее про Allure).
Этот генератор отчетов работает с каждым TestInfo
после завершения теста, преобразует информацию о шагах в информацию о шагах Allure JSON, а затем печатает JSON в LogCat в следующем формате:
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: TEST PASSED
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: #AllureStepsInfoJson#: [{"attachments":[],"name":"My step 1","parameters":[],"stage":"finished","start":1568790287246,"status":"passed", "steps":[],"stop":1568790288184}]
Эти журналы должны обрабатываться вашим тестовым оркестратором (например, Marathon). Если вы используете Marathon, вы должны знать, что он требует некоторых дополнительных модификаций для поддержки обработки этих журналов и в настоящий момент не работает должным образом. Но мы усердно работаем над этим.
Действия по умолчанию в разделах до/после
Иногда разработчик хочет поместить некоторые действия, повторяющиеся во всех тестах до/после, в одно место, чтобы упростить поддержку тестов.
Существуют аннотации @beforeTest/@afterTest
для решения указанных задач. Но у разработчика нет доступа к BaseTestContext
в этих методах.
Вот почему мы ввели специальные действия по умолчанию, которые вы можете установить в конструкторе с помощью Kaspresso.Builder
.
Пример реализации действий по умолчанию в Kaspresso.Builder
:
open class YourTestCase : TestCase(
kaspressoBuilder = Kaspresso.Builder.simple {
beforeEachTest {
testLogger.i("beforeTestFirstAction")
}
afterEachTest {
testLogger.i("afterTestFirstAction")
}
}
)
beforeEachTest
:
beforeEachTest(override = true, action = {
testLogger.i("beforeTestFirstAction")
})
afterEachTest
аналогичен beforeEachTest
. Если вы установите
override
в false
, то последнее beforeAction
будет относиться к родительскому TestCase плюс текущий action
. В противном случае последний beforeAction
будет только текущим action
.
Чтобы понять, как это работает и как переопределить (или просто расширить) действие по умолчанию, пожалуйста,
обратите внимание на пример.
Device
Экземпляр Device
. Подробная информация находится на этой странице в разделе Вики.
AdbServer
Экземпляр AdbServer
. Подробная информация находится на этой странице в разделе Вики.
Настройка Kaspresso и пример перехватчиков Kaspresso
Пример того, как настроить Kaspresso и как использовать перехватчики Kaspresso, находится здесь.
Настройки Kaspresso по умолчанию
BaseTestCase
, TestCase
, BaseTestCaseRule
, TestCaseRule
используют настроенный по умолчанию Kaspresso (Kaspresso.Builder.simple конфигуратор
).
Ниже приведены наиболее ценные функции настроенного по умолчанию Kaspresso.
Ведение журнала
Просто запустите SimpleTest. Далее вы увидите эти логи:
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: BEFORE TEST SECTION
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: TEST SECTION
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "1. Open Simple Screen" in SimpleTest
I/KASPRESSO_SPECIAL: I am kLogger
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@95afab5' assertion on view (with id: com.kaspersky.kaspressample:id/activity_main_button_next)
I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_next;text=Next;)
I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_next;text=Next;)
I/KASPRESSO: TEST STEP: "1. Open Simple Screen" in SimpleTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "2. Click button_1 and check button_2" in SimpleTest
I/KASPRESSO: single click on AppCompatButton(id=button_1;text=Button 1;)
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@9f38781' assertion on view (with id: com.kaspersky.kaspressample:id/button_2)
I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=button_2;text=Button 2;)
I/KASPRESSO: TEST STEP: "2. Click button_1 and check button_2" in SimpleTest SUCCEED. It took 0 minutes, 0 seconds and 301 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "3. Click button_2 and check edit" in SimpleTest
I/KASPRESSO: single click on AppCompatButton(id=button_2;text=Button 2;)
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@ad01abd' assertion on view (with id: com.kaspersky.kaspressample:id/edit)
I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;)
E/KASPRESSO: Failed to interact with view matching: (with id: com.kaspersky.kaspressample:id/edit) because of AssertionFailedError
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@d0f1c0a' assertion on view (with id: com.kaspersky.kaspressample:id/edit)
I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;)
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@3b62c7b' assertion on view (with id: com.kaspersky.kaspressample:id/edit)
I/KASPRESSO: Check with string from resource id: <2131558461> on AppCompatEditText(id=edit;text=Some text;)
I/KASPRESSO: TEST STEP: "3. Click button_2 and check edit" in SimpleTest SUCCEED. It took 0 minutes, 2 seconds and 138 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "4. Check all possibilities of edit" in SimpleTest
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "4.1. Change the text in edit and check it" in SimpleTest
I/KASPRESSO: replace text on AppCompatEditText(id=edit;text=Some text;)
I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;)
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@dbd9c8' assertion on view (with id: com.kaspersky.kaspressample:id/edit)
I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;)
I/KASPRESSO: TEST STEP: "4.1. Change the text in edit and check it" in SimpleTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "4.2. Change the text in edit and check it. Second check" in SimpleTest
I/KASPRESSO: replace text on AppCompatEditText(id=edit;text=111;)
I/KASPRESSO: type text(222) on AppCompatEditText(id=edit;)
I/ViewInteraction: Checking 'com.kaspersky.kaspresso.proxy.ViewAssertionProxy@b8ca74' assertion on view (with id: com.kaspersky.kaspressample:id/edit)
I/KASPRESSO: Check with text: is "222" on AppCompatEditText(id=edit;text=222;)
I/KASPRESSO: TEST STEP: "4.2. Change the text in edit and check it. Second check" in SimpleTest SUCCEED. It took 0 minutes, 0 seconds and 403 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: TEST STEP: "4. Check all possibilities of edit" in SimpleTest SUCCEED. It took 0 minutes, 1 seconds and 488 millis.
I/KASPRESSO: ___________________________________________________________________________
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: AFTER TEST SECTION
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: TEST PASSED
I/KASPRESSO: ---------------------------------------------------------------------------
I/KASPRESSO: #AllureStepsInfoJson#: [{"attachments":[],"name":"My step 1","parameters":[],"stage":"finished","start":1568790287246,"status":"passed", "steps":[],"stop":1568790288184}]
I/KASPRESSO: ---------------------------------------------------------------------------
Защита от flaky тестов
Если происходит сбой, Kaspresso пытается исправить его, используя большой набор разнообразных способов.
Эта защита работает для каждого действия и проверки каждого View Kakao и Kautomator! Вам просто нужно расширить свой тестовый класс из TestCase
(BaseTestCase
) или установить TestCaseRule
(BaseTestCaseRule
) в вашем тесте.
Перехватчики
Включенные по умолчанию перехватчики:
- Watcher interceptors
- Behavior interceptors
- Kaspresso interceptors
- BuildStepReportWatcherInterceptor
Все описанные выше возможности доступны благодаря этим перехватчикам.
Несколько слов о Behavior Interceptors
Любая библиотека для UI-тестов нестабильна. Это суровая правда жизни. Любое действие/проверка в вашем тесте может завершиться ошибкой по какой-то неопределенной причине.
Какие общие виды флакающих ошибок существуют:
1. Распространенные плавающие ошибки (флаки), возникающие из-за того, что Espresso/UI Automator был в плохом настроении =)
Вот почему Kaspresso оборачивает все действия/проверки (actions/assertions) Kakao/Kautomator и обрабатывает набор потенциально плавающих исключений.
Если произошло исключение, Kaspresso пытается повторить неудачные действия/проверку в течение 10 секунд. Такая обработка избавляет разработчиков от любых ненадежных действий/проверок.
Подробности доступны по ссылке flakysafety, а примеры — здесь.
2. Невидимость View. В большинстве случаев вам просто нужно прокрутить экран вниз, чтобы View стало видимым. Итак, Kaspresso пытается выполнить это в автоматическом режиме.
Подробности доступны на странице autoscroll.
3. Также Kaspresso пытается закрыть все системные диалоги, если это препятствует выполнению теста.
Подробности доступны на странице systemsafety.
Эти обработки возможны благодаря BehaviorInterceptors
. Кроме того, вы можете установить собственную обработку с помощью Kaspresso.Builder
. Но помните, порядок BehaviorInterceptors
имеет значение: первый элемент будет на самом низком уровне цепочки перехвата, а последний элемент будет на самом высоком уровне.
Рассмотрим принцип работы BehaviorInterceptors
над перехватчиками Kakao. Первый элемент фактически является оболочкой для вызова androidx.test.espresso.ViewInteraction.perform
, второй элемент является оболочкой для первого элемента и так далее.
Взгляните на порядок включения BehaviorInterceptors
по умолчанию в Kaspresso поверх Kakao. Это:
AutoScrollViewBehaviorInterceptor
SystemDialogSafetyViewBehaviorInterceptor
FlakySafeViewBehaviorInterceptor
Под капотом все действия и проверки Kakao в первую очередь вызывают FlakySafeViewBehaviorInterceptor
, который вызывает SystemDialogSafetyViewBehaviorInterceptor
, а тот вызывает AutoScrollViewBehaviorInterceptor
.
Если результатом обработки AutoScrollViewBehaviorInterceptor
является ошибка, то SystemDialogSafetyViewBehaviorInterceptor
пытается обработать полученную ошибку. Если результатом обработки SystemDialogSafetyViewBehaviorInterceptor
также является ошибка, тогда FlakySafeViewBehaviorInterceptor
попытается обработать полученную ошибку.
Для упрощения обсуждаемой темы нарисовали картинку:
Дополнения основной секции
Разработчик также может расширить функциональность параметризованных тестов, предоставив MainSectionEnricher
в BaseTestCase
или BaseTestCaseRule
.
Основная идея - позволить добавить дополнительные шаги тест-кейса до и после главной секции run
.
Все, что вам нужно сделать, это:
- Определите свою реализацию для интерфейса
MainSectionEnricher
;
class LoggingMainSectionEnricher : MainSectionEnricher<TestCaseData> {
...
}
Здесь TestCaseData
- это тот же тип данных, что и в вашей реализации BaseTestCase
.
- Переопределите методы
beforeMainSectionRun
и/илиafterMainSectionRun
, чтобы добавить свои действия до/после;
class LoggingMainSectionEnricher : MainSectionEnricher<TestCaseData> {
override fun TestContext<TestCaseData>.beforeMainSectionRun(testInfo: TestInfo) {
testLogger.d("Before main section run... | ${testInfo.testName}")
step("Check users count...") {
testLogger.d("Check users count: ${data.users.size}")
}
}
override fun TestContext<TestCaseData>.afterMainSectionRun(testInfo: TestInfo) {
testLogger.d("After main section run... | ${testInfo.testName}")
step("Check posts count...") {
testLogger.d("Check posts count: ${data.posts.size}")
}
}
}
В методах beforeMainSectionRun
и afterMainSectionRun
у вас есть полный доступ к свойствам и методам TestContext<TestCaseData
, так что вы можете использовать логгер, добавлять тестовые шаги и так далее. Также, эти методы получили параметр TestInfo
.
- Добавьте написанные классы в свою реализацию
BaseTestCase
.
class EnricherBaseTestCase : BaseTestCase<TestCaseDsl, TestCaseData>(
kaspresso = Kaspresso.Builder.default(),
dataProducer = { action -> TestCaseDataCreator.initData(action) },
mainSectionEnrichers = listOf(
LoggingMainSectionEnricher(),
AnalyticsMainSectionEnricher()
)
)
После того, как это будет сделано, описанные вами действия будут выполняться до или после блока run
основной секции.
Стягивание артефактов с устройства на хост
В зависимости от вашей конфигурации тестов, после выполнения последних на устройстве могут оставаться полезные артефакты: скриншоты, отчеты, видео и т.д.
Для того, чтобы стянуть их с устройства, как правило, программируют специальные скрипты, которые выполняют после завершения тестового прогона на CI. С Kaspresso
вы можете упростить этот процесс. Для этого в Kaspresso Builder'e необходимо сконфигурировать переменную artifactsPullParams
. Пример:
class SomeTest : TestCase(
kaspressoBuilder = Kaspresso.Builder.simple {
artifactsPullParams = ArtifactsPullParams(enabled = true, destinationPath = "artifacts/", artifactsRegex = Regex("(screenshots)|(videos)"))
}
) {
...
}
Для работы этого механизма перед выполнением теста необходимо запустить ADB server. После завершения теста артефакты будут лежать по указанному в аргументе destinationPath
пути относительно
рабочей директории, из которой был запущен ADB server.