こんにちは。我々Avokadoプロジェクトでは、 Androidの中でautotestingについて話を続けます。この記事は、UIテストを作成するための既存のツールの概要と比較です。
テストプロセスが通常どのように見えるかを思い出すことから始めましょう。アプリケーションと対話するエンティティをクライアントと呼びましょう。アプリケーションと対話するために、クライアントには通常、API、REST API、CLI、GUIなどのいくつかのインターフェイスがあります。また、たとえば、APIがクライアントプログラムによって使用される場合、GUIは人間によって使用されます。
アプリケーションの動作に対する期待は、仕様に記載されています。テストの目的は、アプリケーションの動作が仕様の範囲内であることを確認することです。

この問題を解決するために、一連のユースケースまたはテストケースが記録されます。これらは、製品を目的の状態にする一連のステップです。したがって、アプリケーションをテストするプロセスは、すべてのテストケースに合格するプロセスです。
- . , . -.
(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 | + | − | − | + |