Automatyczne testowanie aplikacji Android

Automatyczne testowanie aplikacji Android Arkadiusz Konior ! 4developers ! ! Warszawa 7 kwietnia 2014 Agenda • Testowanie • Android Testing Fra...
Author: Amalia Czech
7 downloads 3 Views 4MB Size
Automatyczne testowanie aplikacji Android Arkadiusz Konior !

4developers ! !

Warszawa 7 kwietnia 2014

Agenda •

Testowanie



Android Testing Framework



Robotium



Espresso



monkey



monkeyrunner



UIAutomator



Robolectric



Porówanie

Android Testing Framework monkeyrunner monkey uiautomator Espresso Robotium Robolectric Spoon Mockito FEST Android android-mock

Selenium NativeDriver Appium MonkeyTalk Selendroid Scirocco Bot-Bot Switchboard Calabash BoundBox RoboSpock

Android Testing Framework monkeyrunner monkey uiautomator Espresso Robotium Robolectric Selenium NativeDriver Appium MonkeyTalk Selendroid Scirocco Bot-Bot Switchboard Spoon Mockito Calabash FEST Android BoundBox android-mock RoboSpock

Cel i koszty •



Zysk •

lepsza jakość aplikacji



bezpieczeństwo zmian

Koszty •

napisanie



utrzymanie



nauka narzędzi

ZYSK > KOSZT

Testowanie •

manualne czy automatyczne



kiedy wdrożyć? prototyp? wersja beta?



Testy •

proste, przejrzyste



niezawodne, deterministyczne @FlakyTest(tolerance=3)!



trwałe - odporne na drobne refaktoryzacje

Testy •

black-box vs white-box



źródła vs. apk



JVM vs. device



czas wykonania



kto pisze? developer? tester?



jedna aplikacja czy wiele?



recorder

TESTY

URZĄDZENIE

JVM

TESTY

URZĄDZENIE

JVM

INSTRUMENTACJA

Android testing framework

Espresso

Robotium

monkey

monkeyrunner

UIAutomator

Robolectric

Instrumentacja • • • • • • • • • •

natywny mechanizm testowy systemu Android dostępne od API 1 jeden proces, różne wątki dwa projekty, dwa apk gradle plugin JUnit 3 zarządzamy cyklem życia testowanej aplikacji wymaga instalacji na urządzeniu/ emulatorze jednostkowe i funkcjonalne symulacja eventów z systemu i od użytkownika

public class MainActivityTest extends ActivityInstrumentationTestCase2 {

! private MainActivity activity;

! public MainActivityTest() { super(MainActivity.class); }

! @Override protected void setUp() throws Exception { super.setUp(); setActivityInitialTouchMode(false); activity = getActivity(); }

! public void testClick() { TextView viewById = (TextView) activity.findViewById(R.id.text); assertEquals("Hello world!", viewById.getText());

! Button button = (Button) activity.findViewById(R.id.button); TouchUtils.clickView(this, button); assertEquals("Clicked", viewById.getText()); } }

Developer machine

application.apk

application-test.apk

Android device/emulator Developer machine

process

application.apk

application-test.apk

app.apk

certyfikat

zarządza app-test.apk

am istrument

Budowanie projektu testowego

Uruchamianie testów

adb

Robotium •

testy funkcjonalne (black-box)



rozszerzenie testów instrumentacyjnych



brak źródeł aplikacji



możliwość nagrywania testów - Robotium Recorder



tekstowe znajdowanie elementów UI



synchronizacja poprzez sleep/retry



interakcja z UI ale nie z kodem aplikacji



click +30 metod

Solo solo = new Solo(getInstrumentation(), getActivity()); solo.sendKey(Solo.MENU); solo.clickOnText("More"); solo.clickOnText("Preferences"); solo.clickOnText("Edit File Extensions"); Assert.assertTrue(solo.searchText("rtf"));

Espresso http://gotgelato.com/espresso/



powstał w Google



cienka warstwa nad instrumentacją (600 linii)



wspiera wersje Android od 2.2



szybki, przejrzysty, łatwo rozszerzalny



ręczna integracja



Leave your waits, syncs, sleeps, and polls behind



Hamcrest matchers

Espresso •

tylko to co może użytkownik - brak getView, getCurrentActivity



contentDescription



pokrycie testami 95%

on view

do stuff

check result

public void testSayHello() { onView(withId(R.id.name_field)) .perform(typeText("Steve")); !

onView(withId(R.id.greet_button)) .perform(click()); !

onView(withText("Hello Steve!")) .check(matches(isDisplayed())); }

monkey



command-line tool



losowy strumień eventów



adb shell monkey -p com.package -v 2000

monkey

monkeyrunner •

nie mylić z monkey



natywny mechanizm



testy funkcjonalne zapisane w skrypcie python



monkeyrunner API: •

MonkeyRunner - połącznie z urządzeniem



MonkeyDevice - instalacja, startowanie activity, keyboard, touch events



MonkeyImage - screenshot

monkeyrunner •

asercje - porównanie zrzutów ekranu sameAs



click x,y



jednocześnie wiele urządzeń



testy regresyjne



sterowane z komputera nie przez adb



wrażliwe na zmianę wyglądu

from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device = MonkeyRunner.waitForConnection() device.installPackage('myproject/bin/MyApplication.apk') package = 'com.example.android.myapplication' activity = 'com.example.android.myapplication.MainActivity' runComponent = package + '/' + activity device.startActivity(component=runComponent) device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP) result = device.takeSnapshot() result.writeToFile('myproject/shot1.png','png')

UIAutomator DEVICE App1

App2

UIAutomator test

Android framework

InputManager

AccessibilityService

UIAutomator •

dostępne w Android SDK od API 16



testy funkcjonalne (black-box)



oparte na JUnit 3



test jako java jar



działa jako niezależny program



Accessibility Manager, Input Manager



testowanie wielu aplikacji



uiautomatorviewer - lepiej niż monkeyrunner



android:contentDescription



integracja z instrumentacją

public class LaunchSettings extends UiAutomatorTestCase {



! public void testDemo() throws UiObjectNotFoundException { getUiDevice().pressHome(); UiObject allAppsButton = new UiObject(new UiSelector().description("Apps")); allAppsButton.clickAndWaitForNewWindow(); UiObject appsTab = new UiObject(new UiSelector().text("Apps")); appsTab.click(); UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true)); appViews.setAsHorizontalList(); UiObject settingsApp = appViews.getChildByText(new UiSelector() .className(android.widget.TextView.class.getName()), "Settings"); settingsApp.clickAndWaitForNewWindow(); UiObject settingsValidation = new UiObject(new UiSelector() .packageName("com.android.settings")); assertTrue("Unable to detect Settings", settingsValidation.exists()); } }

uiautomator

Robolectric •

emulator jest wolny



dex, build, copy - to nie jest TDD



biblioteka mock’ująca Android framework - android.jar



hierarchia shadow - ShadowViewGroup -> ShadowView - zgodne sygnatury metod



możliwość uruchamiania testów na JVM



bez emulatora/urządzenia - JUnit4, Spock



szybkość



“prawdziwe” testy jednostkowe

@RunWith(RobolectricTestRunner.class) public class MyActivityTest {

! @Test public void clickingButton_shouldChangeResultsViewText() throws Exception { Activity activity = Robolectric.buildActivity(MyActivity.class).create().get();

! Button pressMeButton = (Button) activity.findViewById(R.id.press_me_button); TextView results = (TextView) activity.findViewById(R.id.results_text_view);

! pressMeButton.performClick(); String resultsText = results.getText().toString(); assertThat(resultsText, equalTo("Testing Android Rocks!")); } }

oficjalne wsparcie Google nie wymaga urządzenia/emulatora wspiera stare sdk możliwość nagrywania testu możliwość testowania bez źródeł aplikacji asercje wewnętrznego stanu

Robolectric

Robotium

Espresso

UIAutomator

monkey

monkeyrunner

Instrumentation

Porównanie

✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

Które narzędzie wybrać? •

Jak duży projekt?



Etap projektu



Ilość logiki biznesowej, złożoność widoku



Krytyczność błędów



Uruchamiane w IDE czy w CI?



Wspomaganie rozwoju czy zapobieganie regresji?

Q&A

Dziękuję za uwagę

[email protected] http://www.linkedin.com/in/arkadiuszkonior