SlideShare a Scribd company logo
© Zan Markan 2016 - @zmarkan
Android Testing Support Library
The Nitty Gritty
© Zan Markan 2016 - @zmarkan
Testing 101
• on JVM vs on device
• unit / integration / functional / end to end
• Robolectric, Calabash, Instrumentation, Robotium,
Appium
© Zan Markan 2016 - @zmarkan
"Support"
• Android framework vs Support libraries
• Trend to unbundle
• support-v4, appcompat-v7, recyclerview, ...
© Zan Markan 2016 - @zmarkan
"The support library is
basically a mountain
of hacks"
— Chris Banes, Google
© Zan Markan 2016 - @zmarkan
Android Testing
Support Library
© Zan Markan 2016 - @zmarkan
Good Old Times...
• jUnit3 syntax
• Remember
ActivityInstrumentationTestCase2<MainActi
vit>?
© Zan Markan 2016 - @zmarkan
More jUnit3 goodness
• overriding setUp() and tearDown()
• testPrefixedMethods() &
test_prefixedMethods()
• Ignorance Inheritance is bliss
© Zan Markan 2016 - @zmarkan
Welcome to the present
• jUnit4 syntax
• No more extending
• @Test, @Before, @After, @AfterClass,...
• ActivityTestRule, InstrumentationRegistry
© Zan Markan 2016 - @zmarkan
What else is in there?
• Espresso
• More Espresso (there's a lot to it)
• UIAutomator
• Test Runner
• Test Rules
• ...
© Zan Markan 2016 - @zmarkan
What else is in there?
© Zan Markan 2016 - @zmarkan
But First...The setup
(note: AS does that on it's own if you create a new project -
these instructions will mostly apply for legacy projects)
© Zan Markan 2016 - @zmarkan
Gradle
• Set your test runner to be AndroidJUnitRunner
• Add dependencies
• Voila!
© Zan Markan 2016 - @zmarkan
Error:Conflict with dependency 'com.android.support:support-annotations'.
Resolved versions for app (23.2.1) and test app (23.1.1) differ.
See http://g.co/androidstudio/app-test-app-conflict for details.
© Zan Markan 2016 - @zmarkan
Gradle
• Set your test runner to be AndroidJUnitRunner
• Add dependencies
• Voila!
• Resolve dependencies
© Zan Markan 2016 - @zmarkan
Dependency resolutions
• App and Test app depend on different lib versions
• Run ./gradlew :app:dependencies
• ! in the compile and androidTestCompile tasks
© Zan Markan 2016 - @zmarkan
Resolve with
• Force dependency versions in the test APK
• exclude dependency (everywhere applicable)
• use Resolution strategy
© Zan Markan 2016 - @zmarkan
Force versions in test APK
// Resolve conflicts between main and test APK:
androidTestCompile "com.android.support:support-annotations:$rootProject.supportLibraryVersion"
androidTestCompile "com.android.support:support-v4:$rootProject.supportLibraryVersion"
Source: github.com/googlesamples/android-
architecture/blob/todo-mvp/todoapp/app/build.gradle
© Zan Markan 2016 - @zmarkan
Gradle
• Set your test runner to be AndroidJUnitRunner
• Add dependencies
• Resolve dependencies
• Voila!
© Zan Markan 2016 - @zmarkan
© Zan Markan 2016 - @zmarkan
Espresso - components
• View interactions & assertions
• Hamcrest syntax
• No (unnecessary) waits
© Zan Markan 2016 - @zmarkan
Espresso - API
Cheat sheet:
google.github.io/android-testing-support-library/docs/
espresso/cheatsheet
© Zan Markan 2016 - @zmarkan
Poking the screen
onView(withId(R.id.button)).perform(click());
© Zan Markan 2016 - @zmarkan
Poking the screen
onView(withId(R.id.button)).perform(click());
• allOf, anyOf, ...
• withParent, withText...
• isDisplayed, isDialog...
© Zan Markan 2016 - @zmarkan
Espresso - contrib
• RecyclerView
• Drawers
• Pickers
• Accessibility
© Zan Markan 2016 - @zmarkan
Espresso++
• Custom matchers
• Custom ViewActions
• Idling resources
• Page objects
• Intent mocking
© Zan Markan 2016 - @zmarkan
Custom matchers
• Find a view in the hierarchy
• Good for custom views & components
• Override:
• describeTo
• matchesSafely
© Zan Markan 2016 - @zmarkan
Custom matchers
interface MyView{
boolean hasCustomProperty();
}
static BoundedMatcher withCustomPropery() {
return new BoundedMatcher<Object, MyView>(MyView.class){
@Override
public void describeTo(Description description) {
description.appendText("Custom property is enabled");
}
@Override
protected boolean matchesSafely(MyView item) {
return item.hasCustomProperty();
}
};
}
© Zan Markan 2016 - @zmarkan
Custom ViewActions
• Same story as matchers, just a bit more extensive
• example allows us to scroll in NestedScrollView
• github.com/zmarkan/Android-Espresso-
ScrollableScroll
© Zan Markan 2016 - @zmarkan
Custom ViewActions - API
public class ScrollableUtils {
public static ViewAction scrollableScrollTo() {
return actionWithAssertions(new ScrollableScrollToAction());
}
}
© Zan Markan 2016 - @zmarkan
Implementation...
public class ScrollableScrollToAction implements ViewAction{
private static final String TAG = com.zmarkan.nestedscroll.action.ScrollableScrollToAction.class.getSimpleName();
@SuppressWarnings("unchecked")
@Override
public Matcher<View> getConstraints() {
return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf(
isAssignableFromClassOrInterface(ScrollingView.class))));
}
@Override
public void perform(UiController uiController, View view) {
if (isDisplayingAtLeast(90).matches(view)) {
Log.i(TAG, "View is already displayed. Returning.");
return;
}
Rect rect = new Rect();
view.getDrawingRect(rect);
if (!view.requestRectangleOnScreen(rect, true /* immediate */)) {
Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled.");
}
uiController.loopMainThreadUntilIdle();
if (!isDisplayingAtLeast(90).matches(view)) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException(
"Scrolling to view was attempted, but the view is not displayed"))
.build();
}
}
@Override
public String getDescription() {
return "scroll to";
}
}
© Zan Markan 2016 - @zmarkan
Implementation...
@Override
public Matcher<View> getConstraints() {
return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf(
isAssignableFromClassOrInterface(ScrollingView.class))));
}
© Zan Markan 2016 - @zmarkan
Implementation...
@Override
public void perform(UiController uiController, View view) {
if (isDisplayingAtLeast(90).matches(view)) {
Log.i(TAG, "View is already displayed. Returning.");
return;
}
Rect rect = new Rect();
view.getDrawingRect(rect);
if (!view.requestRectangleOnScreen(rect, true /* immediate */)) {
Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled.");
}
uiController.loopMainThreadUntilIdle();
if (!isDisplayingAtLeast(90).matches(view)) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException(
"Scrolling to view was attempted, but the view is not displayed"))
.build();
}
}
© Zan Markan 2016 - @zmarkan
Don't panic.
• Take something that works
• ...like scrollTo() in regular Espresso for ScrollView
• modify it
• profit
© Zan Markan 2016 - @zmarkan
Custom IdlingResource
• A better way to wait
• Use when you have background stuff going on
• Override:
• getName
• isIdleNow
• registerIdleTransitionCallback
© Zan Markan 2016 - @zmarkan
Custom IdlingResource
public class CustomIdlingResource implements IdlingResource{
private ResourceCallback resourceCallback;
private EventBus bus;
private boolean loadingCompleted = false;
public CustomIdlingResource(EventBus bus){
bus.register(this);
}
public void onEvent(LoadingCompletedEvent event){
loadingCompleted = true;
isIdleNow();
}
}
© Zan Markan 2016 - @zmarkan
Custom IdlingResource
@Override
public String getName() {
return CustomIdlingResource.class.getName();
}
@Override
public void registerIdleTransitionCallback(
ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
@Override
public boolean isIdleNow() {
boolean idle = loadingCompleted;
if (idle && resourceCallback != null) {
resourceCallback.onTransitionToIdle();
bus.unregister(this);
}
return idle;
}
}
© Zan Markan 2016 - @zmarkan
Page Object Pattern
• Build your own DSL
• Every screen is a Page
• Page-specific actions and verifications
• (as seen in Calabash, etc...)
© Zan Markan 2016 - @zmarkan
Page Class
public class MainViewTestUtils {
public void enterUserName(String text){
/* espresso goes here
*/ }
public void enterPassword(String text){
/* ... */ }
public void pressContinue(){
/* ... */ }
public void assertErrorShown(boolean shown){ /* ... */ }
}
© Zan Markan 2016 - @zmarkan
Page Class in test
@Test
public void errorShownWhenPasswordIncorrect(){
MainViewTestUtils view = new MainViewTestUtils();
view.enterUsername(username);
view.enterPassword(incorrectPassword);
view.pressContinue();
view.assertErrorShown(true);
}
© Zan Markan 2016 - @zmarkan
To boldly go...
© Zan Markan 2016 - @zmarkan
UI Automator
• Interact with any installed app
• Use to create full end-to-end tests
• Can coexist with Espresso in the same app
• Use uiautomatorviewer command to find items in
the hierarchy
© Zan Markan 2016 - @zmarkan
UI Automator viewer
© Zan Markan 2016 - @zmarkan
UI Automator syntax
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation();
device.pressHome();
device.findObject(new UiSelector().descriptionContains("Google search")).clickAndWaitForNewWindow();
© Zan Markan 2016 - @zmarkan
Test Runner
© Zan Markan 2016 - @zmarkan
Test Runner
• Spins up tests...
• and runs them
• Customise to prepare mocks
• Easier run/debug via command line
© Zan Markan 2016 - @zmarkan
Extending the Runner
• Use custom Application class
• Provide mocked dependencies
• Specify this new runner in build.gradle
• Kotlin Test Runner
© Zan Markan 2016 - @zmarkan
Extending the Runner
public class CustomRunner extends AndroidJUnitRunner{
@Override
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return Instrumentation.newApplication(TestApplication.class, context);
}
}
© Zan Markan 2016 - @zmarkan
Running on the Command
line
• Run module/package/class/method
• Run Large/Medium/Small test only
• Shard to run in parallel
• Debug without reinstalling
© Zan Markan 2016 - @zmarkan
Simple API
• send commands to runner via ADB (adb shell
[commands])
• am instrument -w -e class
your.full.classname#methodName
your.test.package.name/
your.test.Runner.class
• d.android.com/tools/testing/testing_otheride.html
© Zan Markan 2016 - @zmarkan
Test Rules
© Zan Markan 2016 - @zmarkan
Test Rules
• Set starting activity / Service
• Replace ActivityInstrumentationTestCase2
• (in most cases)
• Add / Extend to create more components
© Zan Markan 2016 - @zmarkan
Test Rules - examples
• MockWebServerRule - sets up MockWebServer
when required
• Source: github.com/artem-zinnatullin/
qualitymatters
© Zan Markan 2016 - @zmarkan
© Zan Markan 2016 - @zmarkan
Firebase test lab
• Simple setup
• CI support (via gcloud)
• Support for VMs
• firebase.google.com/docs/test-lab
• Robo test for automated testing
© Zan Markan 2016 - @zmarkan
Espresso Test
Recorder
• Since AS 2.2 preview 3
• Generates test code after clicking on screen
• (Not necessarily nice code)
• tools.android.com/tech-docs/test-recorder
© Zan Markan 2016 - @zmarkan
Above & Beyond?
• Espresso Web for WebViews
• JankTestHelper
• Stuff is being added.
© Zan Markan 2016 - @zmarkan
Best of all?
© Zan Markan 2016 - @zmarkan
It's all open source!
© Zan Markan 2016 - @zmarkan
Pusher
/ˈpʊʃ ər/
noun
1. Platform of APIs for building highly connected apps
2. Hiring in London !
© Zan Markan 2016 - @zmarkan
fin
• ! www.spacecowboyrocketcompany.com
• " @zmarkan
• # zan at markan dot me
• $ androidchat.co (zmarkan)
• %& @zmarkan
© Zan Markan 2016 - @zmarkan
© Zan Markan 2016 - @zmarkan
• google.github.io/android-testing-support-library/
contribute
• Quality Matters - Artem Zinnatulin
• d.android.com/tools/testing-support-library
• github.com/googlesamples/android-testing
• chiuki.github.io/advanced-android-espresso
© Zan Markan 2016 - @zmarkan
• Espresso: Brian Legate (Flickr)
• Hyperdrive: Youtube
• Road Runner: BrownZelip (Flickr)
• Back to the future: Youtube
• Titanic / unit tests passing: Twitter
© Zan Markan 2016 - @zmarkan

More Related Content

PDF
Reactive Streams and RxJava2
PDF
Apache Camel - FUSE community day London 2010 presentation
PDF
Developing, Testing and Scaling with Apache Camel - UberConf 2015
PDF
Reactive Thinking in Java with RxJava2
PDF
JavaFX JumpStart @JavaOne 2016
PDF
Cross-browser testing in the real world
PDF
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Angular Summit 2015
PDF
Spring Boot & Actuators
Reactive Streams and RxJava2
Apache Camel - FUSE community day London 2010 presentation
Developing, Testing and Scaling with Apache Camel - UberConf 2015
Reactive Thinking in Java with RxJava2
JavaFX JumpStart @JavaOne 2016
Cross-browser testing in the real world
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Angular Summit 2015
Spring Boot & Actuators

What's hot (20)

PDF
Overview of the AngularJS framework
PDF
Using ReactJS in AngularJS
PDF
Java Intro: Unit1. Hello World
PDF
Test Driven Development with JavaFX
PPTX
Angular2 for Beginners
PPTX
Vue js and Dyploma
PDF
The Happy Path: Migration Strategies for Node.js
PDF
Cloud Foundy Java Client V 2.0 #cf_tokyo
PDF
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Rich Web Experie...
PDF
Vaadin and Spring at Devoxx UK 2015
PDF
Epoxy 介紹
PDF
Behaviour Driven Development con Behat & Drupal
PDF
Zero downtime deploys for Rails apps
PDF
Android Building, Testing and reversing
PDF
The Modern Java Web Developer - JavaOne 2013
KEY
Enterprise Build And Test In The Cloud
PDF
Spring Boot and Microservices
PDF
Spring boot
PDF
Introduction of React.js
PPTX
Spring Boot Tutorial
Overview of the AngularJS framework
Using ReactJS in AngularJS
Java Intro: Unit1. Hello World
Test Driven Development with JavaFX
Angular2 for Beginners
Vue js and Dyploma
The Happy Path: Migration Strategies for Node.js
Cloud Foundy Java Client V 2.0 #cf_tokyo
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Rich Web Experie...
Vaadin and Spring at Devoxx UK 2015
Epoxy 介紹
Behaviour Driven Development con Behat & Drupal
Zero downtime deploys for Rails apps
Android Building, Testing and reversing
The Modern Java Web Developer - JavaOne 2013
Enterprise Build And Test In The Cloud
Spring Boot and Microservices
Spring boot
Introduction of React.js
Spring Boot Tutorial
Ad

Viewers also liked (20)

PPTX
Android Automation & Testing
PDF
Hololens: Primo Contatto - Marco Dal Pino - Codemotion Milan 2016
PDF
Nobody likes working with you - Luigi G. Valle - Codemotion Milan 2016
PPTX
Hearthstone: an analysis of game network protocols - Marco Cuciniello, Andrea...
PDF
Put yourself in the appsec pipe - Paolo Perego - Codemotion Milan 2016
PPTX
Virtual Reality gaming: analysis of Yon Paradox development - Fabio Mosca - C...
PPTX
Pronti per la legge sulla data protection GDPR? No Panic! - Stefano Sali, Dom...
PDF
Keynote: Community Innovation Alaina Percival - Codemotion Milan 2016
PDF
Keynote: The Most Important Thing - Mike Lee - Codemotion Milan 2016
PPTX
The game design behind Redout - Giuseppe Enrico Franchi - Codemotion Milan 2016
PDF
Wearable Botnets and Happy Hacked Drivers - Andrea Pompili - Codemotion Milan...
ODP
Milano Chatbots Meetup - Paolo Montrasio - Codemotion Milan 2016
ODP
Elixir and Lambda talk with a Telegram bot - Paolo Montrasio - Codemotion Mil...
PDF
Games of Simplicity - Pozzi; Molinari - Codemotion Milan 2016
PDF
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
PDF
Public speaking 4 geeks - Lorenzo Barbieri - Codemotion Milan 2016
PDF
Big Data, Small Dashboard - Andrea Maietta - Codemotion Milan 2016
PPTX
Microservices done right or SOA lessons learnt - Sean Farmar - Codemotion Mil...
PDF
Come rendere il proprio prodotto una bomba creandogli una intera community in...
PDF
Understanding Angular 2 - Shmuela Jacobs - Codemotion Milan 2016
Android Automation & Testing
Hololens: Primo Contatto - Marco Dal Pino - Codemotion Milan 2016
Nobody likes working with you - Luigi G. Valle - Codemotion Milan 2016
Hearthstone: an analysis of game network protocols - Marco Cuciniello, Andrea...
Put yourself in the appsec pipe - Paolo Perego - Codemotion Milan 2016
Virtual Reality gaming: analysis of Yon Paradox development - Fabio Mosca - C...
Pronti per la legge sulla data protection GDPR? No Panic! - Stefano Sali, Dom...
Keynote: Community Innovation Alaina Percival - Codemotion Milan 2016
Keynote: The Most Important Thing - Mike Lee - Codemotion Milan 2016
The game design behind Redout - Giuseppe Enrico Franchi - Codemotion Milan 2016
Wearable Botnets and Happy Hacked Drivers - Andrea Pompili - Codemotion Milan...
Milano Chatbots Meetup - Paolo Montrasio - Codemotion Milan 2016
Elixir and Lambda talk with a Telegram bot - Paolo Montrasio - Codemotion Mil...
Games of Simplicity - Pozzi; Molinari - Codemotion Milan 2016
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Public speaking 4 geeks - Lorenzo Barbieri - Codemotion Milan 2016
Big Data, Small Dashboard - Andrea Maietta - Codemotion Milan 2016
Microservices done right or SOA lessons learnt - Sean Farmar - Codemotion Mil...
Come rendere il proprio prodotto una bomba creandogli una intera community in...
Understanding Angular 2 - Shmuela Jacobs - Codemotion Milan 2016
Ad

Similar to Android Testing Support Library: The Nitty Gritty - Zan Markan - Codemotion Milan 2016 (20)

PPTX
Testing android apps with espresso
PDF
A guide to Android automated testing
PDF
Android UI Testing with Espresso
PDF
Justin Ison
PPTX
Android testing
PPTX
Espresso workshop
PDF
Building Maintainable Android Apps (DroidCon NYC 2014)
PPTX
Xamarin.UITest. From "Zero" to "Hero"
PDF
Espresso devoxx 2014
PDF
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
PDF
Automated Exploratory Testing
PDF
Guide to the jungle of testing frameworks
PPTX
Unit testing without Robolectric, Droidcon Berlin 2016
PPTX
Xam expertday
PPTX
Android Testing
PDF
Robotium Tutorial
PDF
Rockstar Android Testing (Mobile TechCon Munich 2014)
PDF
Testing and Building Android
PPTX
Suparna - XCUITest
Testing android apps with espresso
A guide to Android automated testing
Android UI Testing with Espresso
Justin Ison
Android testing
Espresso workshop
Building Maintainable Android Apps (DroidCon NYC 2014)
Xamarin.UITest. From "Zero" to "Hero"
Espresso devoxx 2014
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
Automated Exploratory Testing
Guide to the jungle of testing frameworks
Unit testing without Robolectric, Droidcon Berlin 2016
Xam expertday
Android Testing
Robotium Tutorial
Rockstar Android Testing (Mobile TechCon Munich 2014)
Testing and Building Android
Suparna - XCUITest

More from Codemotion (20)

PDF
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
PDF
Pompili - From hero to_zero: The FatalNoise neverending story
PPTX
Pastore - Commodore 65 - La storia
PPTX
Pennisi - Essere Richard Altwasser
PPTX
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
PPTX
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
PPTX
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
PPTX
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
PDF
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
PDF
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
PDF
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
PDF
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
PDF
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
PDF
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
PPTX
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
PPTX
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
PDF
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
PDF
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
PDF
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
PDF
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Pompili - From hero to_zero: The FatalNoise neverending story
Pastore - Commodore 65 - La storia
Pennisi - Essere Richard Altwasser
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019

Recently uploaded (20)

PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Encapsulation theory and applications.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
TLE Review Electricity (Electricity).pptx
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
Spectroscopy.pptx food analysis technology
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Programs and apps: productivity, graphics, security and other tools
SOPHOS-XG Firewall Administrator PPT.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Group 1 Presentation -Planning and Decision Making .pptx
cloud_computing_Infrastucture_as_cloud_p
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Advanced methodologies resolving dimensionality complications for autism neur...
Reach Out and Touch Someone: Haptics and Empathic Computing
Encapsulation theory and applications.pdf
NewMind AI Weekly Chronicles - August'25-Week II
Unlocking AI with Model Context Protocol (MCP)
TLE Review Electricity (Electricity).pptx
Encapsulation_ Review paper, used for researhc scholars
Diabetes mellitus diagnosis method based random forest with bat algorithm
Mobile App Security Testing_ A Comprehensive Guide.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Spectroscopy.pptx food analysis technology
Building Integrated photovoltaic BIPV_UPV.pdf
Machine learning based COVID-19 study performance prediction
Programs and apps: productivity, graphics, security and other tools

Android Testing Support Library: The Nitty Gritty - Zan Markan - Codemotion Milan 2016

  • 1. © Zan Markan 2016 - @zmarkan
  • 2. Android Testing Support Library The Nitty Gritty © Zan Markan 2016 - @zmarkan
  • 3. Testing 101 • on JVM vs on device • unit / integration / functional / end to end • Robolectric, Calabash, Instrumentation, Robotium, Appium © Zan Markan 2016 - @zmarkan
  • 4. "Support" • Android framework vs Support libraries • Trend to unbundle • support-v4, appcompat-v7, recyclerview, ... © Zan Markan 2016 - @zmarkan
  • 5. "The support library is basically a mountain of hacks" — Chris Banes, Google © Zan Markan 2016 - @zmarkan
  • 6. Android Testing Support Library © Zan Markan 2016 - @zmarkan
  • 7. Good Old Times... • jUnit3 syntax • Remember ActivityInstrumentationTestCase2<MainActi vit>? © Zan Markan 2016 - @zmarkan
  • 8. More jUnit3 goodness • overriding setUp() and tearDown() • testPrefixedMethods() & test_prefixedMethods() • Ignorance Inheritance is bliss © Zan Markan 2016 - @zmarkan
  • 9. Welcome to the present • jUnit4 syntax • No more extending • @Test, @Before, @After, @AfterClass,... • ActivityTestRule, InstrumentationRegistry © Zan Markan 2016 - @zmarkan
  • 10. What else is in there? • Espresso • More Espresso (there's a lot to it) • UIAutomator • Test Runner • Test Rules • ... © Zan Markan 2016 - @zmarkan
  • 11. What else is in there? © Zan Markan 2016 - @zmarkan
  • 12. But First...The setup (note: AS does that on it's own if you create a new project - these instructions will mostly apply for legacy projects) © Zan Markan 2016 - @zmarkan
  • 13. Gradle • Set your test runner to be AndroidJUnitRunner • Add dependencies • Voila! © Zan Markan 2016 - @zmarkan
  • 14. Error:Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (23.2.1) and test app (23.1.1) differ. See http://g.co/androidstudio/app-test-app-conflict for details. © Zan Markan 2016 - @zmarkan
  • 15. Gradle • Set your test runner to be AndroidJUnitRunner • Add dependencies • Voila! • Resolve dependencies © Zan Markan 2016 - @zmarkan
  • 16. Dependency resolutions • App and Test app depend on different lib versions • Run ./gradlew :app:dependencies • ! in the compile and androidTestCompile tasks © Zan Markan 2016 - @zmarkan
  • 17. Resolve with • Force dependency versions in the test APK • exclude dependency (everywhere applicable) • use Resolution strategy © Zan Markan 2016 - @zmarkan
  • 18. Force versions in test APK // Resolve conflicts between main and test APK: androidTestCompile "com.android.support:support-annotations:$rootProject.supportLibraryVersion" androidTestCompile "com.android.support:support-v4:$rootProject.supportLibraryVersion" Source: github.com/googlesamples/android- architecture/blob/todo-mvp/todoapp/app/build.gradle © Zan Markan 2016 - @zmarkan
  • 19. Gradle • Set your test runner to be AndroidJUnitRunner • Add dependencies • Resolve dependencies • Voila! © Zan Markan 2016 - @zmarkan
  • 20. © Zan Markan 2016 - @zmarkan
  • 21. Espresso - components • View interactions & assertions • Hamcrest syntax • No (unnecessary) waits © Zan Markan 2016 - @zmarkan
  • 22. Espresso - API Cheat sheet: google.github.io/android-testing-support-library/docs/ espresso/cheatsheet © Zan Markan 2016 - @zmarkan
  • 24. Poking the screen onView(withId(R.id.button)).perform(click()); • allOf, anyOf, ... • withParent, withText... • isDisplayed, isDialog... © Zan Markan 2016 - @zmarkan
  • 25. Espresso - contrib • RecyclerView • Drawers • Pickers • Accessibility © Zan Markan 2016 - @zmarkan
  • 26. Espresso++ • Custom matchers • Custom ViewActions • Idling resources • Page objects • Intent mocking © Zan Markan 2016 - @zmarkan
  • 27. Custom matchers • Find a view in the hierarchy • Good for custom views & components • Override: • describeTo • matchesSafely © Zan Markan 2016 - @zmarkan
  • 28. Custom matchers interface MyView{ boolean hasCustomProperty(); } static BoundedMatcher withCustomPropery() { return new BoundedMatcher<Object, MyView>(MyView.class){ @Override public void describeTo(Description description) { description.appendText("Custom property is enabled"); } @Override protected boolean matchesSafely(MyView item) { return item.hasCustomProperty(); } }; } © Zan Markan 2016 - @zmarkan
  • 29. Custom ViewActions • Same story as matchers, just a bit more extensive • example allows us to scroll in NestedScrollView • github.com/zmarkan/Android-Espresso- ScrollableScroll © Zan Markan 2016 - @zmarkan
  • 30. Custom ViewActions - API public class ScrollableUtils { public static ViewAction scrollableScrollTo() { return actionWithAssertions(new ScrollableScrollToAction()); } } © Zan Markan 2016 - @zmarkan
  • 31. Implementation... public class ScrollableScrollToAction implements ViewAction{ private static final String TAG = com.zmarkan.nestedscroll.action.ScrollableScrollToAction.class.getSimpleName(); @SuppressWarnings("unchecked") @Override public Matcher<View> getConstraints() { return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf( isAssignableFromClassOrInterface(ScrollingView.class)))); } @Override public void perform(UiController uiController, View view) { if (isDisplayingAtLeast(90).matches(view)) { Log.i(TAG, "View is already displayed. Returning."); return; } Rect rect = new Rect(); view.getDrawingRect(rect); if (!view.requestRectangleOnScreen(rect, true /* immediate */)) { Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled."); } uiController.loopMainThreadUntilIdle(); if (!isDisplayingAtLeast(90).matches(view)) { throw new PerformException.Builder() .withActionDescription(this.getDescription()) .withViewDescription(HumanReadables.describe(view)) .withCause(new RuntimeException( "Scrolling to view was attempted, but the view is not displayed")) .build(); } } @Override public String getDescription() { return "scroll to"; } } © Zan Markan 2016 - @zmarkan
  • 32. Implementation... @Override public Matcher<View> getConstraints() { return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf( isAssignableFromClassOrInterface(ScrollingView.class)))); } © Zan Markan 2016 - @zmarkan
  • 33. Implementation... @Override public void perform(UiController uiController, View view) { if (isDisplayingAtLeast(90).matches(view)) { Log.i(TAG, "View is already displayed. Returning."); return; } Rect rect = new Rect(); view.getDrawingRect(rect); if (!view.requestRectangleOnScreen(rect, true /* immediate */)) { Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled."); } uiController.loopMainThreadUntilIdle(); if (!isDisplayingAtLeast(90).matches(view)) { throw new PerformException.Builder() .withActionDescription(this.getDescription()) .withViewDescription(HumanReadables.describe(view)) .withCause(new RuntimeException( "Scrolling to view was attempted, but the view is not displayed")) .build(); } } © Zan Markan 2016 - @zmarkan
  • 34. Don't panic. • Take something that works • ...like scrollTo() in regular Espresso for ScrollView • modify it • profit © Zan Markan 2016 - @zmarkan
  • 35. Custom IdlingResource • A better way to wait • Use when you have background stuff going on • Override: • getName • isIdleNow • registerIdleTransitionCallback © Zan Markan 2016 - @zmarkan
  • 36. Custom IdlingResource public class CustomIdlingResource implements IdlingResource{ private ResourceCallback resourceCallback; private EventBus bus; private boolean loadingCompleted = false; public CustomIdlingResource(EventBus bus){ bus.register(this); } public void onEvent(LoadingCompletedEvent event){ loadingCompleted = true; isIdleNow(); } } © Zan Markan 2016 - @zmarkan
  • 37. Custom IdlingResource @Override public String getName() { return CustomIdlingResource.class.getName(); } @Override public void registerIdleTransitionCallback( ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } @Override public boolean isIdleNow() { boolean idle = loadingCompleted; if (idle && resourceCallback != null) { resourceCallback.onTransitionToIdle(); bus.unregister(this); } return idle; } } © Zan Markan 2016 - @zmarkan
  • 38. Page Object Pattern • Build your own DSL • Every screen is a Page • Page-specific actions and verifications • (as seen in Calabash, etc...) © Zan Markan 2016 - @zmarkan
  • 39. Page Class public class MainViewTestUtils { public void enterUserName(String text){ /* espresso goes here */ } public void enterPassword(String text){ /* ... */ } public void pressContinue(){ /* ... */ } public void assertErrorShown(boolean shown){ /* ... */ } } © Zan Markan 2016 - @zmarkan
  • 40. Page Class in test @Test public void errorShownWhenPasswordIncorrect(){ MainViewTestUtils view = new MainViewTestUtils(); view.enterUsername(username); view.enterPassword(incorrectPassword); view.pressContinue(); view.assertErrorShown(true); } © Zan Markan 2016 - @zmarkan
  • 41. To boldly go... © Zan Markan 2016 - @zmarkan
  • 42. UI Automator • Interact with any installed app • Use to create full end-to-end tests • Can coexist with Espresso in the same app • Use uiautomatorviewer command to find items in the hierarchy © Zan Markan 2016 - @zmarkan
  • 43. UI Automator viewer © Zan Markan 2016 - @zmarkan
  • 44. UI Automator syntax UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation(); device.pressHome(); device.findObject(new UiSelector().descriptionContains("Google search")).clickAndWaitForNewWindow(); © Zan Markan 2016 - @zmarkan
  • 45. Test Runner © Zan Markan 2016 - @zmarkan
  • 46. Test Runner • Spins up tests... • and runs them • Customise to prepare mocks • Easier run/debug via command line © Zan Markan 2016 - @zmarkan
  • 47. Extending the Runner • Use custom Application class • Provide mocked dependencies • Specify this new runner in build.gradle • Kotlin Test Runner © Zan Markan 2016 - @zmarkan
  • 48. Extending the Runner public class CustomRunner extends AndroidJUnitRunner{ @Override public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return Instrumentation.newApplication(TestApplication.class, context); } } © Zan Markan 2016 - @zmarkan
  • 49. Running on the Command line • Run module/package/class/method • Run Large/Medium/Small test only • Shard to run in parallel • Debug without reinstalling © Zan Markan 2016 - @zmarkan
  • 50. Simple API • send commands to runner via ADB (adb shell [commands]) • am instrument -w -e class your.full.classname#methodName your.test.package.name/ your.test.Runner.class • d.android.com/tools/testing/testing_otheride.html © Zan Markan 2016 - @zmarkan
  • 51. Test Rules © Zan Markan 2016 - @zmarkan
  • 52. Test Rules • Set starting activity / Service • Replace ActivityInstrumentationTestCase2 • (in most cases) • Add / Extend to create more components © Zan Markan 2016 - @zmarkan
  • 53. Test Rules - examples • MockWebServerRule - sets up MockWebServer when required • Source: github.com/artem-zinnatullin/ qualitymatters © Zan Markan 2016 - @zmarkan
  • 54. © Zan Markan 2016 - @zmarkan
  • 55. Firebase test lab • Simple setup • CI support (via gcloud) • Support for VMs • firebase.google.com/docs/test-lab • Robo test for automated testing © Zan Markan 2016 - @zmarkan
  • 56. Espresso Test Recorder • Since AS 2.2 preview 3 • Generates test code after clicking on screen • (Not necessarily nice code) • tools.android.com/tech-docs/test-recorder © Zan Markan 2016 - @zmarkan
  • 57. Above & Beyond? • Espresso Web for WebViews • JankTestHelper • Stuff is being added. © Zan Markan 2016 - @zmarkan
  • 58. Best of all? © Zan Markan 2016 - @zmarkan
  • 59. It's all open source! © Zan Markan 2016 - @zmarkan
  • 60. Pusher /ˈpʊʃ ər/ noun 1. Platform of APIs for building highly connected apps 2. Hiring in London ! © Zan Markan 2016 - @zmarkan
  • 61. fin • ! www.spacecowboyrocketcompany.com • " @zmarkan • # zan at markan dot me • $ androidchat.co (zmarkan) • %& @zmarkan © Zan Markan 2016 - @zmarkan
  • 62. © Zan Markan 2016 - @zmarkan
  • 63. • google.github.io/android-testing-support-library/ contribute • Quality Matters - Artem Zinnatulin • d.android.com/tools/testing-support-library • github.com/googlesamples/android-testing • chiuki.github.io/advanced-android-espresso © Zan Markan 2016 - @zmarkan
  • 64. • Espresso: Brian Legate (Flickr) • Hyperdrive: Youtube • Road Runner: BrownZelip (Flickr) • Back to the future: Youtube • Titanic / unit tests passing: Twitter © Zan Markan 2016 - @zmarkan