Automatisiertes Testen in Android

Post on 23-Jun-2015

644 views 3 download

description

Speaker: Arne Limburg open knowledge GmbH MobileTechCon

transcript

Arne Limburg | open knowledge GmbH

@ArneLimburg @_openknowledge

Meine Person Arne Limburg Head of Development open knowledge GmbH

@ArneLimburg @_openknowledge

www.openknowledge.de

Herausforderungen

•  Vielfalt der Geräte •  Bildschirmauflösung •  Eingabemethode •  Capabilities

•  Vielfalt der Umwelteinflüsse •  Umgebung (Netz, Batterie, Standort) •  Nutzerverhalten

Was tun?

Rechne mit allem!

Rechne mit nichts!

Testen, Testen, Testen!

Testen

•  Konzentration auf das Wesentliche – Geräte – Android-Versionen – Länder – Operatoren

•  Test-Automatisierung

Unit-Tests

Testen - Agenda

1

2

3

4

Funktionstests

Abnahme- und Regressionstests

Stresstests

Unit-Tests

Unit-Testing

„A unit is the smallest testable part of an application.“ http://en.wikipedia.org/wiki/Unit_testing

Ziel von Unit-Testing

•  korrekte Funktionsweise von kleinen Einheiten der Software (Testen einzelner Methoden)

•  Automatisch •  Regelmäßig (Continuous Integration) •  Regressionssicher

Android Testing Framework

•  JUnit-Unterstützung für On-Device-Testing

•  Oberklassen zum Testen von Android-Komponenten

•  Activity •  Content-Provider •  Service •  …

Mock-Kontexte

•  MockContext •  Alle Methoden werfen Exception

•  IsolatedContext •  Isolation vom Device •  Datenbank- und Datei-Operationen möglich

•  RenamingDelegatingContext •  Kommunikation mit dem Device möglich •  Datenbank- und Datei-Operationen werden

umgeleitet

Android Testing - Architektur

Unit-Test-Klassenhierarchie junit.framework.TestCase

AndroidTestCase InstrumentationTestCase

Package android.test

ApplicationTestCase

LoaderTestCase

ProviderTestCase2

ServiceTestCase

ActivityTestCase

ActivityUnitTestCase

ActivityInstrumentationTestCase2

PoviderTestCase2

•  Testen eines isolierten Content-Providers •  Verwendung von IsolatedContext •  Bereitstellen eines MockContentResolvers API setContext(Context) (von AndroidTestCase) getMockContentResolver() getProvider

ProviderTestCase2 public class PositionProviderTest extends ProviderTestCase2<PositionProvider> { public PositionProviderTest() { super(PositionProvider.class, PositionProvider.AUTHORITY); } public void testInsert() { … }

ProviderTestCase2 public class PositionProviderTest extends ProviderTestCase2<PositionProvider> { public PositionProviderTest() { super(PositionProvider.class, PositionProvider.AUTHORITY); } public void testInsert() { … }

ProviderTestCase2 public class PositionProviderTest extends ProviderTestCase2<PositionProvider> { public PositionProviderTest() { super(PositionProvider.class, PositionProvider.AUTHORITY); } public void testInsert() { … }

ServiceTestCase

•  Standardmäßig mit „echtem“ Context und MockApplication

•  Herausforderung: Testen von Threading API setApplication(Application) setContext(Context) (von AndroidTestCase) startService(Intent) bindService(Intent)

ServiceTestCase public class UpdaterServiceTest extends ServiceTestCase<UpdaterService> { public UpdaterServiceTest() { super(UpdaterService.class); } public void testStartService() { … } }

ServiceTestCase public class UpdaterServiceTest extends ServiceTestCase<UpdaterService> { public UpdaterServiceTest() { super(UpdaterService.class); } public void testStartService() { … } }

ServiceTestCase public class UpdaterServiceTest extends ServiceTestCase<UpdaterService> { public UpdaterServiceTest() { super(UpdaterService.class); } public void testStartService() { … } }

Code Diving ...

ActivityUnitTestCase

•  Leitet von InstrumentationTestCase ab •  Isoliertes Testen einer Activity API (Auszug) getStartedActivityIntent() getStartedActivityRequest() getRequestOrientation() isFinishedCalled()

ActivityUnitTestCase public class Positio…ActivityUnitTest extends ActivityUnitTestCase<Position…Activity> { public PositionOverviewActivityUnitTest() { super(PositionOverviewActivity.class); } public void testOnListItemClick() { … } }

ActivityUnitTestCase public class Positio…ActivityUnitTest extends ActivityUnitTestCase<Position…Activity> { public PositionOverviewActivityUnitTest() { super(PositionOverviewActivity.class); } public void testOnListItemClick() { … } }

ActivityUnitTestCase public class Positio…ActivityUnitTest extends ActivityUnitTestCase<Position…Activity> { public PositionOverviewActivityUnitTest() { super(PositionOverviewActivity.class); } public void testOnListItemClick() { … } }

Code Diving ...

Unit-Tests •  Herausforderung:

Umgang mit Abhängigkeiten •  Klassisches Vorgehen:

Erstellen von Mocks •  On-Device: Mock-Implementierungen des

Android Testing Frameworks •  Off-Device: Gängige Java-Mocking-

Frameworks (EasyMock, Mockito, ...)

Off-Device-Testing •  Herausforderung:

Android ≠ Java java.lang.RuntimeException: Stub! Off-Device

–  Instantiieren –  Mocking via Java-Mocking-Frameworks –  Zugriff auf Android-Interna

•  Lösung: Robolectric

Robolectric •  Instantiieren von Android-Klassen •  Shadowing •  Zugriff auf Resourcen •  ...

Robolectric @RunWith(RobolectricTestRunner.class) public class PositionOverviewActivityTest { @Test public void onItemClick() { … } … }

Robolectric @RunWith(RobolectricTestRunner.class) public class PositionOverviewActivityTest { @Test public void onItemClick() { … } … }

Robolectric @Test public void onItemClick() { … ShadowActivity a = shadowOf(activity); Intent startedIntent = a.getNextStartedActivity(); … }

Code Diving ...

Continuous Integration

•  Regelmäßiges Bauen und Testen (CI-Server)

z.B. Jenkins •  Voraussetzung: Automatisiertes Bauen

und Testen Ant oder Maven

•  Zusatzfeature: Code-Abdeckung mit EMMA

Unit-Tests

Agenda

1

2

3

4

Funktionstests

Abnahme- und Regressionstests

Stresstests

Unit-Tests

Funktionstests

Funktionstests •  Testen der Interaktion mit der Umgebung •  Testaufbau

•  UI-Verhalten •  Klickpfade •  State-Saving / -Restoring

•  Testinhalt •  Änderung der Konfiguration (Orientierung,

Sprache, Tastatur, Location) •  Änderung der Ressourcen (Batterie, Netzwerk,

Bluetooth, GPS •  Eingehender Anruf / SMS

•  Tool: Auch Android JUnit

Unit-Test-Klassenhierarchie junit.framework.TestCase

AndroidTestCase InstrumentationTestCase

Package android.test

ApplicationTestCase

LoaderTestCase

ProviderTestCase2

ServiceTestCase

ActivityTestCase

ActivityUnitTestCase

ActivityInstrumentationTestCase2

InstrumentationTestCase •  API (Auszug)

<T> T launchActivity(String, Class<T>, Bundle) <T> T launchActivityWithIntent(String, Class<T>, Intent) void sendKeys(String) void sendKeys(int…) void sendRepeatedKeys(int…) Instrumentation getInstrumentation()

Instrumentation •  API (Auszug)

ActivityMonitor addMonitor(…) Activity waitForMonitor(…) Activity waitForMonitorWithTimeout(…) void startActivitySync(…) void sendXXXSync(…) void startPerformanceSnapshot() void endPerformanceSnapshot() void startProfiling() Void stopProfiling()

ActivityInstrumentationTestCase2

•  Leitet von InstrumentationTestCase ab •  Testen von UI-Verhalten

à Testen eines gesamten Worksflows •  Erzeugen von TouchEvents mit TouchUtils

•  Überprüfen von Layout mit ViewAsserts •  Eventuell Verwendung von Third-Party-

Framework (Robotium)

ActivityInstrumentationTestCase2 public class Position…ActivityUiTest extends ActivityInstrumentationTestCase2<Pos…ity> { public PositionOverviewActivityUiTest() { super(PositionOverviewActivity.class); } public void testClickOnList() { … } }

ActivityInstrumentationTestCase2 public class Position…ActivityUiTest extends ActivityInstrumentationTestCase2<Pos…ity> { public PositionOverviewActivityUiTest() { super(PositionOverviewActivity.class); } public void testClickOnList() { … } }

ActivityInstrumentationTestCase2 public class Position…ActivityUiTest extends ActivityInstrumentationTestCase2<Pos…ity> { public PositionOverviewActivityUiTest() { super(PositionOverviewActivity.class); } public void testClickOnList() { … } }

Code Diving ...

ActivityUnitTestCase vs. ActivityInstrumentationTestCase2 ActivityUnitTestCase •  Reines Testen des

Codes •  Kein Test des UI-

Verhaltens •  Kein Test des

Workflow-Verhaltens

ActivityInstr…TestCase2 •  Testen des UI-

Verhaltens •  Testen des Workflow-

Verhaltens

Robotium

•  Selenium nur für Android •  Baut auf Instrumentation auf •  Weniger komplex zu bedienen •  Black-Box-Testing möglich

Code Diving ...

Android Emulator fernsteuern

•  Steuerung von Geo-Koordinaten, Telefonie, Netzwerk (Geschwindigkeit, Delay), Batterie, SMS, Sensoren

•  DDMS-Perspektive in Eclipse •  Verbinden via Telnet

Beispiel: telnet localhost 5554

Continuous Integration

Best Practice •  Funktionstests selten ausführen •  Klassifizierung von Tests

@SmallTest – „Echter“ Unit-Test (ActivityUnitTest) @MediumTest – Test einer Komponente mit Umgebung @LargeTest – Workflow-Test (gesamter Use-Case)

Unit-Tests

Agenda

1

2

3

4

Funktionstests

Abnahme- und Regressionstests

Stresstests

Funktionstests

Abnahme- und Regressionstests

MonkeyRunner

Creative Commons by Simon Englisch

MonkeyRunner

•  Python / Jython •  Testen kompletter Use-Cases •  Vergleichen der Ergebnisse über

Bildschirm-Fotos •  Paralleles Testen verschiedener

Devices und Auflösungen via Scripting

MonkeyRunner MonkeyRunner API void alert(…), integer choice(…), string input(…) void sleep(…) MonkeyDevice waitForConnection(…)

MonkeyDevice API (Auszug) void installPackage(…) void startActivity(…) Void broadcastIntent(…) void drag(…), void press(…), void touch(…), void type(…) MonkeyImage takeSnapshot()

MonkeyImage API (Auszug) MonkeyImage getSubImage(…), boolean sameAs(…), void writeToFile(…)

Unit-Tests

Agenda

1

2

3

4

Funktionstests

Abnahme- und Regressionstests

Stresstests

Abnahme- und Regressionstests

Stresstests

Würden Sie einen Affen mit Ihrem Telefon spielen lassen?

© Rex Features

Monkey

•  Schicken zufälliger Events •  Anzahl und Geschwindigkeit

konfigurierbar •  Reihenfolge reproduzierbar (durch

Angabe von seed) •  Wahrscheinlichkeit einzelner Event-

Arten konfigurierbar àSuchen von spezifischen Bugs

Unit-Tests

Agenda

1

2

3

4

Funktionstests

Regressionstests

Stresstests Stresstests

Fazit - Testing

•  Unit-Tests •  Off Device (Robolectric) •  On Device (Android Testing Framework) •  Regelmäßig (Continuous Integration) mit

Simulator •  Vor der Auslieferung mit echten Geräten

•  Funktionale Tests •  UI-Interaktion •  Gesamter Workflow (automatisiert)

•  Regressionstests (MonkeyRunner) •  Stresstests (Monkey)

Vielen Dank für Ihre Zeit. Kontakt: open knowledge GmbH Bismarckstr. 13 26122 Oldenburg arne.limburg@openknowledge.de @ArneLimburg @_openknowledge

Q&A