مرحبا. نحن في Avokado Project نواصل الحديث عن الاختبار التلقائي في Android. هذه المقالة هي نظرة عامة ومقارنة للأدوات الموجودة لكتابة اختبارات واجهة المستخدم.
لنبدأ بالتذكير بالشكل الذي تبدو عليه عادة عملية الاختبار. دعنا نسمي الكيان الذي يتفاعل مع التطبيق العميل. للتفاعل مع التطبيق ، عادة ما يكون لدى العميل العديد من الواجهات المتاحة: API ، REST API ، CLI ، 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 | + | − | − | + |