Share
Embed
Единственное, что вам нужно для UI-тестирования
Егор Курников, Лаборатория Касперского at #MOSDROID 19 Potassium [in KasperskyLab HeadQuarter]
При написании UI-тестов для мобильных Android-приложений возникает множество различных проблем. Часть из них может быть решена с помощью ряда уже существующих инструментов, другая часть каждой компанией решается по-своему, эти решения довольно специфичны и не могут быть транслированы. Остальные проблемы остаются без решения.
Мы хотели создать универсальный фреймворк, который будет предоставлять готовый рецепт приготовления UI-тестов, а также обладать гибким API для расширения и кастомизации. Расскажу, как мы это делали, и что из этого получилось.
MOSDROID
September 13, 2019
Transcript
178 slides
-
➔ Как начать писать автотесты? ➔ Какие инструменты выбрать? Зачем
нам фреймворк? 2 -
➔ Как начать писать автотесты? ➔ Какие инструменты выбрать? ➔
Что делать если нужного инструмента нет? Зачем нам фреймворк? 4 -
➔ Как начать писать автотесты? ➔ Какие инструменты выбрать? ➔
Что делать если нужного инструмента нет? Зачем нам фреймворк? 5 -
@RunWith(AndroidJUnit4::class) class TypeLoginTest { @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java) @Test
fun test() { onView(withId(R.id.login_input_view)) .perform(typeText(“MyLogin”)) .check(matches(withText(“MyLogin”)) } } 7 -
@RunWith(AndroidJUnit4::class) class TypeLoginTest { @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java) @Test
fun test() { onView(withId(R.id.login_input_view)) .perform(typeText(“MyLogin”)) .check(matches(withText(“MyLogin”)) } } 7 -
@RunWith(AndroidJUnit4::class) class TypeLoginTest { @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java) @Test
fun test() { onView(withId(R.id.login_input_view)) .perform(typeText(“MyLogin”)) .check(matches(withText(“MyLogin”)) } } 7 -
@RunWith(AndroidJUnit4::class) class TypeLoginTest { @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java) @Test
fun test() { onView(withId(R.id.login_input_view)) .perform(typeText(“MyLogin”)) .check(matches(withText(“MyLogin”)) } } 7 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android Чего мы хотим? 14 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 14 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 16 -
val button = KButton { withId(R.id.my_btn) } val textView =
KTextView { withBackgroundColor(R.color.primary) isDescendantOfA { withId(R.id.content) withMatcher(MyCustomMatcher()) } } KView 19 -
val button = KButton { ... } val textView =
KTextView { ... } btn.click() textView { isVisible() hasText(R.string.title) } KView 20 -
open class KBaseView<out T> : BaseActions, BaseAssertions { override val
view: ViewInteraction ... } 21 -
open class KBaseView<out T> : BaseActions, BaseAssertions { override val
view: ViewInteraction ... } 21 -
open class KBaseView<out T> : BaseActions, BaseAssertions { override val
view: ViewInteraction ... } 21 -
interface BaseActions { val view: ViewInteraction fun click() { ...
} fun doubleClick() { ... } fun longClick() { ... } fun scrollTo() { view.perform( ViewActions.scrollTo() ) } ... } interface BaseAssertions { val view: ViewInteraction fun isDisplayed() { ... } fun isVisible() { ... } fun hasBackgroundColor() { ... } fun isClickable() { view.check( ViewAssertions.matches( ViewMatchers.isClickable() ) ) } ... } 22 -
interface BaseActions { val view: ViewInteraction fun click() { ...
} fun doubleClick() { ... } fun longClick() { ... } fun scrollTo() { view.perform( ViewActions.scrollTo() ) } ... } interface BaseAssertions { val view: ViewInteraction fun isDisplayed() { ... } fun isVisible() { ... } fun hasBackgroundColor() { ... } fun isClickable() { view.check( ViewAssertions.matches( ViewMatchers.isClickable() ) ) } ... } 22 -
interface BaseActions { val view: ViewInteraction fun click() { ...
} fun doubleClick() { ... } fun longClick() { ... } fun scrollTo() { view.perform( ViewActions.scrollTo() ) } ... } interface BaseAssertions { val view: ViewInteraction fun isDisplayed() { ... } fun isVisible() { ... } fun hasBackgroundColor() { ... } fun isClickable() { view.check( ViewAssertions.matches( ViewMatchers.isClickable() ) ) } ... } 22 -
class FormScreen : Screen<FormScreen>() { val login = KEditText {
withId(R.id.login) } val password = KEditText { withId(R.id.password) } val submitBtn = KButton { withText(“Submit”) } val backBtn = KButton { withId(R.id.back) } } Submit login Sign in password Page object 23 -
@Test fun test() { MainScreen() { nextButton { isVisible() click()
} } SecondScreen() { button1.isVisible() button2.click() } ThirdScreen() { editText { isVisible() hasText(R.string.my_text) } } } 24 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 25 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 25 -
open class KBaseView<out T> : BaseActions, BaseAssertions { override val
view: ViewInteraction ... } 30 -
open class KBaseView<out T> : BaseActions, BaseAssertions { override val
view: ViewInteractionDelegate ... } 30 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
@Before fun setup() { Kakao.intercept { onViewInteraction { onCheck {
interaction, assertion -> Log.d("KAKAO", "$interaction is checking $assertion") } onPerform { interaction, action -> Log.d("KAKAO", "$interaction is performing $action") } onAll { interaction -> Log.d("KAKAO", "$interaction") } } onDataInteraction { ... } onWebInteraction { ... } } } 31 -
Flaky safety fun <T> flakySafely(action: () -> T): T {
var cachedException: Throwable var startTime = System.currentTimeMillis() do { try { return action.invoke() } catch (e: Throwable) { Thread.sleep(intervalMs) cachedException = e } } while(System.currentTimeMillis() - startTime <= timeoutMs) throw cachedException } 34 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 38 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 38 -
class ViewActionProxy( private val viewAction: ViewAction ): ViewAction { fun
perform(ui: UiController, view: View) { Log.d(TAG, “${viewAction.descr} on ${view.descr}”) viewAction.perform(ui, view) } } interaction.perform(ViewActionProxy(viewAction)) 43 BehaviorInterceptors -
class ViewActionProxy( private val viewAction: ViewAction ): ViewAction { fun
perform(ui: UiController, view: View) { Log.d(TAG, “${viewAction.descr} on ${view.descr}”) viewAction.perform(ui, view) } } interaction.perform(ViewActionProxy(viewAction)) 43 BehaviorInterceptors -
class ViewActionProxy( private val viewAction: ViewAction ): ViewAction { fun
perform(ui: UiController, view: View) { watcherInterceptors.forEach { it.intercept(ui, view) } viewAction.perform(ui, view) } } interaction.perform(ViewActionProxy(viewAction)) 44 BehaviorInterceptors -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 46 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 46 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 46 -
➔ Accessibility ➔ Activities ➔ Apps ➔ Exploit ➔ Files
➔ Keyboard ➔ Location ➔ Network ➔ Permissions ➔ Phone ➔ Screenshots Device 47 -
➔ Accessibility ➔ Activities ➔ Apps ➔ Exploit ➔ Files
➔ Keyboard ➔ Location ➔ Network ➔ Permissions ➔ Phone ➔ Screenshots interface Apps { fun install(apkPath: String) fun uninstall(pckgName: String) fun launch(pckgName: String, data: Uri?) fun openRecent(contentDescr: String) fun kill(pckgName: String) } Device 48 -
➔ Accessibility ➔ Activities ➔ Apps ➔ Exploit ➔ Files
➔ Keyboard ➔ Location ➔ Network ➔ Permissions ➔ Phone ➔ Screenshots Device interface Files { fun push( serverPath: String, devicePath: String ) fun remove(path: String) } 49 -
➔ Accessibility ➔ Activities ➔ Apps ➔ Exploit ➔ Files
➔ Keyboard ➔ Location ➔ Network ➔ Permissions ➔ Phone ➔ Screenshots Device interface Network { fun enable() fun disable() fun enableWiFi() fun disableWiFi() } 50 -
Что умеет ADB? ➔ Установка apk ➔ push/pull ➔ Выставление
системных настроек 51 -
Что умеет ADB? ➔ Установка apk ➔ push/pull ➔ Выставление
системных настроек adb emu ➔ Установка геопозиции ➔ Выставление скорости сети, задержки ➔ Симуляция вызовов ➔ Выставление значений акселерометра ➔ Имитация работы с отпечатком пальца 51 -
Virtual routing 10.0.2.2 - Special alias to your loopback interface
(i.e. 127.0.0.1 on your development machine) 53 -
$ adb shell generic_x86:/ # ifconfig radio0 Link encap:Ethernet HWaddr
7a:7f:dd:f9:55:3r inet addr:192.168.200.2 Bcast:192.168.200.255 Mask 255.255.255.0 inet6 addr: fec0::4072:df55:c06e:32bc/64 Scope: Site inet6 addr: fe80::787f:bcff:fef0:444e/64 Scope: Link inet6 addr: fec0::787f:bcff:fef0:444e/64 Scope: Site UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1191 errors:0 dropped:0 overruns:0 frame:0 TX packets:1314 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:436242 TX bytes: 127317 lo Link encap:Local loopback inet addr:127.0.0.1 Mask 255.0.0.0 inet6 addr: ::1/128 Scope: Host UP LOOPBACK RUNNING MULTICAST MTU:655536 Metric:1 RX packets:38 errors:0 dropped:0 overruns:0 frame:0 TX packets:38 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:4542 TX bytes: 4542 wlan0 Link encap:Ethernet HWaddr 01:22:33:44:55:66 Driver mac80211_hwsim inet addr:192.168.232.2 Bcast:192.168.239.255 Mask 255.255.248.0 inet6 addr: fe80::ff:fe44:5566/64 Scope: Link inet6 addr: fec0::61d3:bc35:c84d:1be3/64 Scope: Site inet6 addr: fec0::ff:fe44:5566/64 Scope: Site UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:50545 errors:0 dropped:0 overruns:0 frame:0 TX packets:34184 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:52675660 TX bytes: 6458247 56 -
$ adb shell generic_x86:/ # ifconfig lo Link encap:Local loopback
inet addr:127.0.0.1 Mask 255.0.0.0 inet6 addr: ::1/128 Scope: Host UP LOOPBACK RUNNING MULTICAST MTU:655536 Metric:1 RX packets:38 errors:0 dropped:0 overruns:0 frame:0 TX packets:38 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:4542 TX bytes: 4542 57 -
Port forwarding ➔ adb forward tcp:6100 tcp:8500 HOST localhost:8500 GET
localhost:6100 localhost:6100 59 -
Client app App Test app Server localhost:8500 Tests HOST Client
localhost: 6100 61 -
Client app App adb forward tcp:6100 tcp:8500 Client localhost: 8500
Test app Tests HOST 62 Client localhost: 6100 Server localhost:8500 -
Client app App Test app Tests HOST 63 Client localhost:
6100 Client localhost: 8500 Server localhost:8500 -
adb forward ... Cli ent app Server App Cli ent
app Server App Cli ent app Server App adb forward ... adb forward ... HOST 64 Client localhost: 6100 -
class AdbServer { fun performCmd( vararg commands: String ): String<String>
fun performAdb( vararg commands: String ): String<String> fun perfromShell( vararg commands: String ): String<String> fun disconnectServer() } 1. Connect 2. performAdb("...") 3. Execute "..." 5. Disconnect 65 Client localhost: 8500 Server localhost:8500 4. Command complete -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 66 -
➔ Хорошая читаемость ➔ Стабильность ➔ Логирование ➔ Скриншоты ➔
Работа с OS Android ➔ Архитектура Чего мы хотим? 66 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest { private val mainScreen = MainScreen() private
val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 68 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest { private val mainScreen = MainScreen() private
val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @get:Rule val testCaseRule = TestCaseRule(javaClass.simpleName) @Test fun test() { ... } } 69 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase() { private val mainScreen =
MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 70 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder().apply { ... } )
{ private val mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 71 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder.default() ) { private val
mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 72 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder.default().apply { ... } )
{ private val mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 73 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder.default().apply { viewBehaviorInterceptors = mutableListOf()
} ) { private val mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 74 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder.default().apply { viewBehaviorInterceptors.add(MyInterceptor()) } )
{ private val mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 75 Kaspresso -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest : TestCase( Kaspresso.Builder.default().apply { viewBehaviorInterceptors.add(MyInterceptor()) flakySafetyParams.timeoutMs =
1_000 } ) { private val mainScreen = MainScreen() private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 76 Kaspresso -
abstract class TestCase( kaspressoBuilder: Kaspresso.Builder ) { internal val kaspresso:
Kaspresso = kaspressoBuilder.build() ... } Kaspresso initialization 77 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 78 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 78 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 78 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 78 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { private val mainScreen = MainScreen()
private val homeScreen = HomeScreen() @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) @Test fun test() { ... } } 79 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { MainScreen()
{ homeButton.click() } HomeScreen() { title { isVisible() hasAnyText() } } } } 80 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { //1st
step MainScreen() { homeButton.click() } //2nd step HomeScreen() { title { isVisible() hasAnyText() } } } } 81 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { //1st
step Log.i(“1 step started”) MainScreen() { homeButton.click() } Log.i(“1st step succeeded”) //2nd step Log.i(“2nd step started”) HomeScreen() { title { isVisible() hasAnyText() } } Log.i(“2nd step succeeded”) } } 82 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { //1st
step try { Log.i(“1st step started”) MainScreen() { homeButton.click() } Log.i(“1st step succeeded”) } catch(e: Throwable) { Log.i(“1st step failed”) takeScreenshot() throw e } //2nd step ... } } 83 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { step(“1.
Open Home screen”) { MainScreen() { homeButton.click() } } step(“2. Check Home title”) { HomeScreen() { title { isVisible() hasAnyText() } } } } } 84 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { step("1.
Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } 85 -
action.invoke() throw exception next step step success step fail interceptBefore()
interceptFinally() interceptFailure() interceptSuccess() step start start success fail ➔ Logging ➔ Screenshots ➔ ... StepInterceptors 86 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 87 -
I/KASPRESSO: ___________________________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home screen" in
OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: ___________________________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_1;text=Button 1;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 301 millis. I/KASPRESSO: ___________________________________________________________________________ I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check with string from resource id: <2131558461> on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 2 seconds and 138 millis. I/KASPRESSO: ___________________________________________________________________________ 88 -
I/KASPRESSO: _____________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home screen" in
OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: ______________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_1;text=Button 1;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 301 millis. I/KASPRESSO: ___________________________________________________________________________ I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check with string from resource id: <2131558461> on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 2 seconds and 138 millis. I/KASPRESSO: ___________________________________________________________________________ 89 -
I/KASPRESSO: _____________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home screen" in
OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_home;text=Home;) E/KASPRESSO: Failed to interact with view matching: (with id: actibity_main_button_back) because of AssertionFailedError I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest FAILED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: ______________________________________________________________ 90 -
I/KASPRESSO: _____________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home screen" in
OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_home;text=Home;) E/KASPRESSO: Failed to interact with view matching: (with id: actibity_main_button_back) because of AssertionFailedError I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest FAILED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: ______________________________________________________________ 91 sdcard/screenshots OpenHomeScreenTest_step_1_failure Sign in -
@Test fun test() { step("Pass first run wizzard") { scenario(
FirstRunWizzardScenario() ) step("Substep #1") { ... } step("Substep #2") { step("Inner substep #3") { ... } } } } 92 -
@Test fun test() { step("Pass first run wizzard") { scenario(
FirstRunWizzardScenario() ) step("Substep #1") { ... } step("Substep #2") { step("Inner substep #3") { ... } } } } 92 -
@Test fun test() { step("Pass first run wizzard") { scenario(
FirstRunWizzardScenario() ) step("Substep #1") { ... } step("Substep #2") { step("Inner substep #3") { ... } } } } 92 -
@Test fun test() { step("Pass first run wizzard") { scenario(
FirstRunWizzardScenario() ) step("Substep #1") { ... } step("Substep #2") { step("Inner substep #3") { ... } } } } class FirstRunWizzardScenario : Scenario() { override val steps: TestContext<Unit>.() -> Unit = { step("Check first wizzard screen") { ... } step("Check second wizzard screen") { ... } } } 92 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { step("1.
Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } 93 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { step("0.
Turn off wifi") { ... } step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } 94 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { step("0.
Turn off wifi") { ... } step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } step("8. Turn on wifi") { ... } } } 95 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ turnOffWiFi() }.after { turnOnWiFi() }.run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } } 96 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ device.network.toggleWiFi(enable = false) }.after { device.network.toggleWiFi(enable = true) }.run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } } 97 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 98 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context device.files.push() device.phone.emulateCall(NUMBER) device.location.enableGps() device.exploit.pressBack() device.screenshots.take(TAG) 99 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 100 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... }.run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } step("4. Check some stuff is done") { ... } step("5. Do another stuff") { ... } step("6. Check another stuff is done") { ... } step("7. 42") { ... } } } } 101 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .init { company { name = "Microsoft"; city = "Redmond" } company { name = "Google"; city = "Mountain View" } owner { firstName = "Satya"; secondName = "Nadella" } owner { firstName = "Sundar"; secondName = "Pichai" } } .run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } ... } } } 102 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .init { company { name = "Microsoft"; city = "Redmond" } company { name = "Google"; city = "Mountain View" } owner { firstName = "Satya"; secondName = "Nadella" } owner { firstName = "Sundar"; secondName = "Pichai" } }.transform { bind(ownerSurname = "Nadella", companyName = "Microsoft") bind(ownerSurname = "Pichai", companyName = "Google") } .run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } ... } } } 103 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .init { company { name = "Microsoft"; city = "Redmond" } company { name = "Google"; city = "Mountain View" } owner { firstName = "Satya"; secondName = "Nadella" } owner { firstName = "Sundar"; secondName = "Pichai" } }.transform { bind(ownerSurname = "Nadella", companyName = "Microsoft") bind(ownerSurname = "Pichai", companyName = "Google") } .run { step("1. Check description") { MainScreen().descriptionTextView { hasText(data.owners.first().firstName ?: "") } } } } } 104 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 105 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 105 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .init { ... }.transform { ...} .run { step("1. Open Home screen") { testLogger.i("I am test logger") MainScreen() { homeButton.click() } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 106 -
I/KASPRESSO: _____________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home screen" in
OpenHomeScreenTest I/KASPRESSO_SPECIAL: I am test logger I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=activity_main_button_home;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: ______________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_1;text=Button 1;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 301 millis. I/KASPRESSO: ___________________________________________________________________________ I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest I/KASPRESSO: single click on AppCompatButton(id=button_2;text=Button 2;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: Check with string from resource id: <2131558461> on AppCompatEditText(id=edit;text=Some text;) I/KASPRESSO: TEST STEP: "3. Do some stuff" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 2 seconds and 138 millis. I/KASPRESSO: ___________________________________________________________________________ 107 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 108 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .run { step("1. Open Home screen") { MainScreen() { homeButton.click() } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 109 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .run { step("1. Open Home screen") { adbServer.performAdb( "adb push foo.txt /sdcard/foo.txt" ) MainScreen() { homeButton.click() } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 110 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 111 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .run { step("1. Open Home screen") { MainScreen() { flakySafely(timeoutMs = 7_000) { homeButton.click() } } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 112 -
➔ device ➔ data ➔ testLogger ➔ adbServer ➔ flakySafely
➔ compose Test context 113 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .run { step("1. Open Home screen") { MainScreen() { compose { or(redBtn) { hasText("blue") } or(blueBtn) { hasText("blue") } } homeButton.click() } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 114 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... }.after { ... } .run { step("1. Open Home screen") { MainScreen() { redBtn.compose { or { hasText("blue") } or { hasText("red") } } homeButton.click() } } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 115 -
@RunWith(AndroidJUnit4::class) class OpenHomeScreenTest: TestCase() { @Test fun test() { before
{ ... } .after { ... } .init { ... } .transform { ...} .run { step("1. Open Home screen") { ... } step("2. Check Home title") { ... } step("3. Do some stuff") { ... } } } } 116 -
step #2 step #1 step #3 run before after step
#2 Test runner Test report success fail success fail success fail TestRunInterceptors ➔ Logging ➔ Screenshots ➔ ... start start start start success fail 117 -
data class Kaspresso( internal val libLogger: UiTestLogger, internal val testLogger:
UiTestLogger, internal val device: Device, internal val adbServer: AdbServer, internal val flakySafetyParams: FlakySafetyParams, internal val autoScrollParams: AutoScrollParams, internal val viewActionWatcherInterceptors: List<ViewActionWatcherInterceptor>, internal val viewAssertionWatcherInterceptors: List<ViewAssertionWatcherInterceptor>, internal val atomWatcherInterceptors: List<AtomWatcherInterceptor>, internal val webAssertionWatcherInterceptors: List<WebAssertionWatcherInterceptor>, internal val viewBehaviorInterceptors: List<ViewBehaviorInterceptor>, internal val dataBehaviorInterceptors: List<DataBehaviorInterceptor>, internal val webBehaviorInterceptors: List<BehaviorInterceptor>, internal val stepInterceptors: List<StepInterceptor>, internal val testRunInterceptors: List<TestRunInterceptor> ) Kaspresso configuration 118 -
I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home Screen" in OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;) I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST PASSED I/KASPRESSO: ---------------------------------------------------------- Sign in screenshots saved at sdcard/screenshots 119 -
I/KASPRESSO: --------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: --------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home Screen" in OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;) I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST PASSED I/KASPRESSO: ---------------------------------------------------------- Sign in screenshots saved at sdcard/screenshots 120 -
I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: TEST SECTION I/KASPRESSO: --------------------------------------------- I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home Screen" in OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;) I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST PASSED I/KASPRESSO: ---------------------------------------------------------- Sign in screenshots saved at sdcard/screenshots 121 -
I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home Screen" in OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;) I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: --------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: --------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: TEST PASSED I/KASPRESSO: ---------------------------------------------------------- Sign in screenshots saved at sdcard/screenshots 122 -
I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "1. Open Home Screen" in OpenHomeScreenTest I/KASPRESSO: Check view has effective visibility=VISIBLE on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: single click on AppCompatButton(id=home_btn;text=Home;) I/KASPRESSO: TEST STEP: "1. Open Home screen" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 618 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: __________________________________________________________ I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest I/KASPRESSO: type text(111) on AppCompatEditText(id=edit;) I/KASPRESSO: Check with text: is "111" on AppCompatEditText(id=edit;text=111;) I/KASPRESSO: TEST STEP: "2. Check Home title" in OpenHomeScreenTest SUCCEED. It took 0 minutes, 0 seconds and 621 millis. I/KASPRESSO: __________________________________________________________ I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: TEST PASSED I/KASPRESSO: --------------------------------------------- Sign in screenshots saved at sdcard/screenshots 123 -
I/KASPRESSO: --------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: --------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=FAILED) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION FAILED I/KASPRESSO: --------------------------------------------- I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: TEST FAILED I/KASPRESSO: ---------------------------------------------------------- Sign in screenshots saved at sdcard/screenshots 124 -
I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: BEFORE TEST SECTION I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: command=shell
svc data disable was performed with result=CommandResult(status=FAILED) I/KASPRESSO: ---------------------------------------------------------- I/KASPRESSO: --------------------------------------------- I/KASPRESSO: AFTER TEST SECTION I/KASPRESSO: --------------------------------------------- I/KASPRESSO: command=shell svc data enable was performed with result=CommandResult(status=SUCCESS) I/KASPRESSO: --------------------------------------------- I/KASPRESSO: TEST FAILED I/KASPRESSO: --------------------------------------------- Sign in screenshots saved at sdcard/screenshots 125 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты ➔ Предоставляет интерфейс взаимодействия с OS Android Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты ➔ Предоставляет интерфейс взаимодействия с OS Android ➔ Умеет в ADB Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты ➔ Предоставляет интерфейс взаимодействия с OS Android ➔ Умеет в ADB ➔ Предоставляет решение по архитектуре Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты ➔ Предоставляет интерфейс взаимодействия с OS Android ➔ Умеет в ADB ➔ Предоставляет решение по архитектуре ➔ Гибко настраивается и конфигурируется Kaspresso 126 -
➔ Читаемость Kakao ➔ Реализует flaky safety ➔ Предоставляет удобный
механизм логирования ➔ Позволяет снимать скриншоты ➔ Предоставляет интерфейс взаимодействия с OS Android ➔ Умеет в ADB ➔ Предоставляет решение по архитектуре ➔ Гибко настраивается и конфигурируется ➔ Может быть кастомизирован Kaspresso 126 -
Our team Евгений Мацюк Андрей Антипов Егор Курников Дмитрий Мовчан
Руслан Мингалиев Александр Блинов Алексей Творогов Николай Нестеров Павел Стрельченко Ринат Агишев 127 Дмитрий Воронин Сергей Занкин