Halo. Kami di Proyek Avokado terus berbicara tentang pengujian otomatis di Android. Artikel ini adalah ikhtisar dan perbandingan alat yang ada untuk menulis tes UI.
Mari kita mulai dengan mengingat seperti apa proses pengujian biasanya. Mari kita sebut entitas yang berinteraksi dengan aplikasi sebagai klien. Untuk berinteraksi dengan aplikasi, klien biasanya memiliki beberapa antarmuka yang tersedia: API, REST API, CLI, GUI, dll. Dan jika, misalnya, API digunakan oleh program klien, maka GUI digunakan oleh manusia.
Ekspektasi perilaku aplikasi dijelaskan dalam spesifikasi. Tujuan pengujian adalah untuk memverifikasi bahwa perilaku aplikasi sesuai dengan spesifikasi.

Untuk mengatasi masalah ini, serangkaian kasus penggunaan atau kasus uji dicatat. Itu adalah urutan langkah yang membawa produk ke keadaan yang diinginkan. Jadi, proses pengujian aplikasi adalah proses melewati semua kasus uji.
- . , . -.
(JUnit, Cucumber). :
- — (assertions).
- . — , .
- .
:
- ;
- ;
- ;
- ;
- ;
- .
, , . , Android-, (Avito test runner, Marathon, Spoon, Fork) , .
API , GUI — .

, GUI-, UI-. unit-, .
GUI- . , . GUI- (Espresso, UiAutomator) « », , , .
API :
- : , , , .
- API .
- .
, , Kakao Kaspresso. . — , — , .

, .
Android- :
- Espresso.
- UiAutomator.
- Robotium.
- Selendroid.
Android Instrumentation Framework — API Android . — Espresso UiAutomator. Google. . .
UiAutomator

UiAutomator Android SDK 16 API. GUI- : , , , , . , — Ui Automator Viewer.
UiAutomator (black-box). . , , . , , :
- ;
- ;
- ;
- , ;
- .
UiAutomator AccessibilityService, . AccessibilityService , . , AccessibilityNodeInfo. View: , .

View AccessibilityEventSource Binder IPC AccessibilityManagerService , , , . AccessibilityManagerService AccessibilityService , , UiAutomator, . AccessibilityService’ UiAutomator’a . View, .
UiAutomator “UI Automator deep diving”.
UiAutomator:
- , Binder IPC, . , UiAutomator , . , . , .
- ,
ViewOpenGL Unity, UiAutomator’a, . , , UiAutomator’a .
, UiAutomator , . Espresso.
Espresso

UI- Google, (white-box). Espresso Android API 10 , . .
Espresso . , .
Espresso — (ViewMatcher), (ViewAction) (ViewAssertion).

Espresso Hamcrest. — , , Espresso — . , , . , .
@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(Visibility.VISIBLE)
));
}
Espresso — Espresso , . . , (idle).

, , , , check ViewInteraction. ViewAssertion idle’.
public ViewInteraction check(ViewAssertion viewAssertion) {
// (...)
runSynchronouslyOnUiThread(new Callable<Void>() {
@Override
public Void call() {
uiController.loopMainThreadUntilIdle();
// (...)
viewAssertion.check(...)
}
});
}
Espresso:
- .
- . , , . Espresso . UiAutomator.
- API Espresso , . .
- Espresso .
, , Espresso — , .
Robotium Selendroid
Robotium Selendroid Espresso UiAutomator. C , . , .
Robotium Android API 8+, ( WebView , , API 15), Java. Robotium Recorder IntelliJ IDEA Android Studio.
Selendroid API — 10 19. WebDriver, Inspector record-and-playback-.
, Robotium Selendroid.
Robolectric
, Robolectric , . , Android UI-. Robolectric unit- JUnit Android API.
Android SDK, shadow-. Robolectric , inflate view, , , - Android-. Robolectric , Android, , JVM. , .
, . , : - . - API, . , . , , , Espresso UiAutomator.
. API , .
, , .
. UI- , . ( . , ). , . . , .
. , , . black-box . . , , black-box , , . white-box, black-box .
. , . , . , , .
. , . : , , , — , , . , , , , . stacktrace’ , , , , .
. . , . , .
adb. adb: / , , .
API. — , . , , , — , . , , . , .
.
Appium

Appium — - open source Android iOS. Appium Selenium WebDriver, web-. . Appium- , . Appium API.

. , Appium . HTTP- Node.JS, WebDriver-, . , , . , , Appium .
. Appium , . Android UiAutomator, Espresso. , , . . Espresso UiAutomator.
API. Appium API, WebDriver. Appium , .
. , , , , ( ), Appium-, , , , . , . — .
. , .
. , .
adb. - Appium’ , adb-. , , .
. Appium . — Espresso . - , .
, Appium — Android- . , Kotlin, Java. - Appium . , . : « . , , », « ».
Kakao

Kakao — Kotlin DSL Espresso. Espresso .
API. Kakao — boilerplate- :
KView— Kakao- , . , Kakao ,KEditText,KButton.. .Screen— - PageObject.Screen— , stateless-KView.Screen, , , .Screen’, .
, , Espresso. :
@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(Visibility.VISIBLE)
));
}
:
object MainScreen : Screen<MainScreen>() {
val hotelName = KTextView { withId(R.id.label_bf_hotelname) }
}
@Test
fun kakaoTest() {
MainScreen {
hotelName {
isVisible()
}
}
}
. Kakao — , Appium, . - . Espresso , , — , ..
. Kakao Espresso, .
. Kakao . API , Espresso-. , , . - - .
. , Espresso. .
. . .
adb. , Espresso.
. , Kakao — DSL Espresso. UiAutomator, API . , , .
Barista

Barista — , Espresso.
API. Kakao, Espresso. Barista — , Espresso-. :
- helper- , Espresso . ,
onView(withId(R.id.button)).perform(click())EspressoclickOn(R.id.button).clickListItem(R.id.list, 4). - Android- Assertions API.
- , .
- runtime permission’.
- test rule’, , flaky- shared preferences, , .
Barista NestedScrollView, Espresso, . DSL , .
. FlakyTestRule . . , .
. - Espresso.
. , Espresso . Espresso.
. , .
. .
adb. , Espresso.
. Barista . , , . .
Kaspresso

- UI-, , .
API. Kakao. Kaspresso Kakao DSL — Kotlin DSL , Kakao Screen’ KView.
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest : TestCase() {
@Test
fun kaspressoTest() {
before { ... }
.after { ... }
.run {
step("1. Open Home screen") {
MainScreen {
openHomeScreenBtn.click()
}
}
step("2. Check Home title") {
HomeScreen {
title.isVisible()
}
}
step("3. Do some stuff") { ... }
}
}
}
Kaspresso API , . , (. How to write autotests).
. Kaspresso - API Espresso UiAutomator. , , , . , , . Kaspresso Kautomator — Kakao-like UiAutomator, Espresso UiAutomator .
object KakaoScreen : Screen<KakaoScreen>() {
val title = KTextView { withText(titleText) }
val btn = KButton { withId(R.id.button1) }
}
object KautomatorScreen : UiScreen<KautomatorScreen>() {
val title = UiTextView { withText(titleText) }
val btn = UiButton { withId(pkgName, R.id.button2) }
}
@Test
fun kaspressoTest() {
KakaoScreen {
title.isVisible()
btn.click()
}
KautomatorScreen {
title.isVisible()
btn.click()
}
}
device. , :
- ;
- ;
- ;
- , , ;
- ;
- ;
- ;
- : back, home, recents.
Kaspresso , .
. Kaspresso , . , , ViewAction ViewAssertion, , . , , , (. Configurator).
. Kaspresso Espresso UiAutomator , , ScrollView, , . helper-. , flakySafely:
MainScreen {
flakySafely {
btn.click()
}
}
. , , .
. . , Kaspresso , . :
device.screenshots.take("MainScreen_step_1")
adb. Kaspresso AdbServer — HTTP-, adb-. , , . , adb- . AdbServer , device. API adb-:
adbServer.performAdb("emu sms send +79111111111 $smsText")
adbServer.perfromShell("rm -f $filePath")
AdbServer , , adb.
| Appium | Kakao | Barista | Kaspresso | |
| API | − | + | ± | + |
| + | − | − | + | |
| − | + | − | + | |
| − | ± | ± | + | |
| − | ± | − | + | |
| − | − | − | + | |
| adb | + | − | − | + |