droidcon 2014 - robotium vs espresso_droidcon

135

Upload: xebia-france

Post on 05-Dec-2014

114 views

Category:

Technology


0 download

DESCRIPTION

Vos tests Robotium sont instables ? Peu lisibles ? Alors venez découvrir Espresso, la nouvelle librairie de testing pour Android. Présentation proposée par Thomas Guérin lors de la DroidCon Fr 2014

TRANSCRIPT

Page 1: DroidCon 2014 - Robotium vs espresso_droidcon
Page 2: DroidCon 2014 - Robotium vs espresso_droidcon
Page 3: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs EspressoGet ready to rumble !

Page 4: DroidCon 2014 - Robotium vs espresso_droidcon
Page 5: DroidCon 2014 - Robotium vs espresso_droidcon

Thomas Guerin

Page 6: DroidCon 2014 - Robotium vs espresso_droidcon

Thomas GuerinDéveloppeur Android

Page 7: DroidCon 2014 - Robotium vs espresso_droidcon

Thomas GuerinDéveloppeur Android

Tests addict

Page 8: DroidCon 2014 - Robotium vs espresso_droidcon

Thomas GuerinDéveloppeur Android

Tests addictNiveau 15 à Destiny

Page 9: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Page 10: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Pourquoi ne pas faire de tests ?

#Droidcon #Robotium #Espresso @Tom404_

Page 11: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Pourquoi ne pas faire de tests ?

“Mes tests durent des heures !”

#Droidcon #Robotium #Espresso @Tom404_

Page 12: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Pourquoi ne pas faire de tests ?

“Mes tests durent des heures !”

#Droidcon #Robotium #Espresso

“Tester ce n’est pas toujours simple !”

@Tom404_

Page 13: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Pourquoi ne pas faire de tests ?

“Mes tests durent des heures !”

#Droidcon #Robotium #Espresso

“Tester ce n’est pas toujours simple !”

“Mes tests échouent aléatoirement !”

@Tom404_

Page 14: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Pourquoi ne pas faire de tests ?

“Mes tests durent des heures !”

#Droidcon #Robotium #Espresso

“Tester ce n’est pas toujours simple !”

“Mes tests échouent aléatoirement !”

“Je vais devoir corriger les tests alors que je n’ai presque rien modifié”

@Tom404_

Page 15: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 16: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un test doit être…

#Droidcon #Robotium #Espresso @Tom404_

Page 17: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un test doit être…

#Droidcon #Robotium #Espresso

Simple

@Tom404_

Page 18: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un test doit être…

#Droidcon #Robotium #Espresso

RapideSimple

@Tom404_

Page 19: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un test doit être…

#Droidcon #Robotium #Espresso

RapideSimple Fiable

@Tom404_

Page 20: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un test doit être…

#Droidcon #Robotium #Espresso

RapideSimple Fiable Durable

@Tom404_

Page 21: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 22: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un mauvais exemple

#Droidcon #Robotium #Espresso @Tom404_

Page 23: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un mauvais exemple

#Droidcon #Robotium #Espresso

// Start the main activity of the application under test mActivity = getActivity(); !// Get a handle to the Activity object's main UI widget, a Spinner mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01); !// Set the Spinner to a known position mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION); !// Stop the activity - The onDestroy() method should save the state of the Spinner mActivity.finish(); !// Re-start the Activity - the onResume() method should restore the state of the Spinner mActivity = getActivity(); !// Get the Spinner's current position int currentPosition = mActivity.getSpinnerPosition(); !// Assert that the current position is the same as the starting position assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

@Tom404_

Page 24: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Un mauvais exemple

#Droidcon #Robotium #Espresso

// Start the main activity of the application under test mActivity = getActivity(); !// Get a handle to the Activity object's main UI widget, a Spinner mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01); !// Set the Spinner to a known position mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION); !// Stop the activity - The onDestroy() method should save the state of the Spinner mActivity.finish(); !// Re-start the Activity - the onResume() method should restore the state of the Spinner mActivity = getActivity(); !// Get the Spinner's current position int currentPosition = mActivity.getSpinnerPosition(); !// Assert that the current position is the same as the starting position assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

@Tom404_

Page 25: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 26: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Les combattants

#Droidcon #Robotium #Espresso @Tom404_

Page 27: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Les combattants

#Droidcon #Robotium #Espresso

Robotium

@Tom404_

Page 28: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Les combattants

#Droidcon #Robotium #Espresso

VS

Robotium Espresso

@Tom404_

Page 29: DroidCon 2014 - Robotium vs espresso_droidcon
Page 30: DroidCon 2014 - Robotium vs espresso_droidcon

Préparation

Page 31: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 32: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Dépendances Gradle

#Droidcon #Robotium #Espresso @Tom404_

Page 33: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Dépendances Gradle

#Droidcon #Robotium #Espresso

dependencies { androidTestCompile ‘com.jayway.android.robotium:robotium-solo:5.2.1' androidTestCompile 'com.squareup.assertj:assertj-android:1.0.0' }

Robotium

@Tom404_

Page 34: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Dépendances Gradle

#Droidcon #Robotium #Espresso

android.packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'LICENSE.txt' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' }

dependencies { /* Jars récupérés depuis https://code.google.com/p/android-test-kit */ androidTestCompile files(‘libs/espresso-1.1.jar’, ‘libs/espresso-contrib-1.1.jar', ‘libs/testrunner-1.1.jar', 'libs/testrunner-runtime-1.1.jar') androidTestCompile 'com.google.guava:guava:14.0.1', 'com.squareup.dagger:dagger:1.1.0', 'org.hamcrest:hamcrest-core:1.1', 'org.hamcrest:hamcrest-integration:1.1', 'org.hamcrest:hamcrest-library:1.1' }

Espresso

@Tom404_

Page 35: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Dépendances Gradle

#Droidcon #Robotium #Espresso

android.packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'LICENSE.txt' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' }

dependencies { androidTestCompile ’com.jakewharton.espresso:espresso:1.1-r3’, ‘com.jakewharton.espresso:espresso-support-v4:1.1-r3' }

https://github.com/JakeWharton/double-espresso

Double Espresso

@Tom404_

Page 36: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 37: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Test Runner

#Droidcon #Robotium #Espresso @Tom404_

Page 38: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Test Runner

#Droidcon #Robotium #Espresso

Robotium utilise le test runner du sdk

@Tom404_

Page 39: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Test Runner

#Droidcon #Robotium #Espresso

Robotium utilise le test runner du sdk

Espresso nécessite un test runner spécifique

@Tom404_

Page 40: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Test Runner

#Droidcon #Robotium #Espresso

Robotium utilise le test runner du sdk

Espresso nécessite un test runner spécifique

defaultConfig { testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner" }

@Tom404_

Page 41: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 42: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

GoogleInstrumentationTestRunner

#Droidcon #Robotium #Espresso @Tom404_

Page 43: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

GoogleInstrumentationTestRunner

#Droidcon #Robotium #Espresso

onCreate de l'application finalisée avant le début des tests

@Tom404_

Page 44: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

GoogleInstrumentationTestRunner

#Droidcon #Robotium #Espresso

onCreate de l'application finalisée avant le début des tests

Instrumentation terminée == activités finies

@Tom404_

Page 45: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

GoogleInstrumentationTestRunner

#Droidcon #Robotium #Espresso

onCreate de l'application finalisée avant le début des tests

Instrumentation terminée == activités finies

Monitoring des activités plus fiable

@Tom404_

Page 46: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

GoogleInstrumentationTestRunner

#Droidcon #Robotium #Espresso

onCreate de l'application finalisée avant le début des tests

Instrumentation terminée == activités finies

Monitoring des activités plus fiable

Peut être utilisé avec d'autres librairies

@Tom404_

Page 47: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 48: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Initialisation

#Droidcon #Robotium #Espresso @Tom404_

Page 49: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Initialisation

#Droidcon #Robotium #Espresso

Robotiumpublic class SimpleActionsTest extends ActivityInstrumentationTestCase2<MainActivity> { ! private Solo solo; ! public void setUp() throws Exception { super.setUp(); solo = new Solo(getInstrumentation(), getActivity()); } ! public void tearDown() throws Exception { solo.finishOpenedActivities(); super.tearDown(); } }

@Tom404_

Page 50: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Initialisation

#Droidcon #Robotium #Espresso

public class SimpleActionsTest extends ActivityInstrumentationTestCase2<MainActivity> { ! @Override protected void setUp() throws Exception { super.setUp(); // Espresso ne va pas lancer l'activité pour nous getActivity(); } }

Espresso

@Tom404_

Page 51: DroidCon 2014 - Robotium vs espresso_droidcon
Page 52: DroidCon 2014 - Robotium vs espresso_droidcon

Expressivité

Page 53: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 54: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

Robotium

@Tom404_

Page 55: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

Solo

Robotium

@Tom404_

Page 56: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

Solo

getView(int viewId)

drag(…)

clickInList(int line, int index)

goBack()setNavigationDrawer(int status)pressSoftKeyboardNextButton()

clickOnActionBarItem(int id)

scrollToBottom() searchEditText(String text)

pressSoftKeyboardSearchButton()

getButton(int index)scrollDown()clearEditText(int index)

clickOnToggleButton(String text)

clickOnImageButton(int index)

clickOnButton(int index)

pressMenuItem(int index)

clickOnActionBarHome()

scrollDownList(int index)

searchText(String text)

@Tom404_

Page 57: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 58: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso @Tom404_

Page 59: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso

// Récupération de la vue Button myButton = (TextView) solo.getView(R.id.my_button); !// Assertions (AssertJ Android) assertThat(myButton).hasText(“My button”).isVisible(); !// Clic sur la vue solo.clickOnView(myButton)

@Tom404_

Page 60: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 61: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso @Tom404_

Page 62: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso

Librairie de matchers

@Tom404_

Page 63: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso

Librairie de matchersassertThat("Hello", equalTo("Hello"))

@Tom404_

Page 64: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso

Librairie de matchersassertThat("Hello", equalTo("Hello"))!// Sucre syntaxique assertThat(“Hello", is("Hello"))

@Tom404_

Page 65: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso

Librairie de matchersassertThat("Hello", equalTo("Hello"))!// Sucre syntaxique assertThat(“Hello", is("Hello"))!// De nombreux matchers disponibles allOf not instanceOf hasProperty equalToIgnoringCase

@Tom404_

Page 66: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest

#Droidcon #Robotium #Espresso

Librairie de matchersassertThat("Hello", equalTo("Hello"))!// Sucre syntaxique assertThat(“Hello", is("Hello"))

Possibilité de composition

!// De nombreux matchers disponibles allOf not instanceOf hasProperty equalToIgnoringCase

@Tom404_

Page 67: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 68: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest custom matcher

#Droidcon #Robotium #Espresso @Tom404_

Page 69: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Hamcrest custom matcher

#Droidcon #Robotium #Espresso

public class IsNotANumber extends TypeSafeMatcher<Double> { ! @Override public boolean matchesSafely(Double number) { return number.isNaN(); } ! public void describeTo(Description description) { description.appendText("not a number"); } ! public static Matcher<Double> notANumber() { return new IsNotANumber(); } !}

@Tom404_

Page 70: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 71: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

Espresso

@Tom404_

Page 72: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

Espresso

@Tom404_

Page 73: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 74: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

click()!typeText(text)

ViewActions

withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 75: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

click()!typeText(text)

ViewActions

doesNotExist()!matches(Matcher<View>)

ViewAssertions

withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 76: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

perform(ViewAction)!check(ViewAssertion)

ViewInteraction / DataInteraction

click()!typeText(text)

ViewActions

doesNotExist()!matches(Matcher<View>)

ViewAssertions

withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 77: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

perform(ViewAction)!check(ViewAssertion)

ViewInteraction / DataInteraction

click()!typeText(text)

ViewActions

doesNotExist()!matches(Matcher<View>)

ViewAssertions

withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 78: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

API overview

#Droidcon #Robotium #Espresso

onView(Matcher<View>)!onData(Matcher<Object>

Espresso

perform(ViewAction)!check(ViewAssertion)

ViewInteraction / DataInteraction

click()!typeText(text)

ViewActions

doesNotExist()!matches(Matcher<View>)

ViewAssertions

withId()!withText(text)!

hasSibling(Matcher<View>)

ViewMatchersEspresso

@Tom404_

Page 79: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 80: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso @Tom404_

Page 81: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso

onView(allOf(withId(R.id.my_button), withText(“My Button”))) .check(matches(isDisplayed())) .perform(click());

@Tom404_

Page 82: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso

onView(allOf(withId(R.id.my_button), withText(“My Button”))) .check(matches(isDisplayed())) .perform(click());!// Une simple extraction de méthode permet de simplifier onView(withIdAndText(R.id.my_button, "My Button”)) .check(matches(isDisplayed())) .perform(click());

@Tom404_

Page 83: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso

onView(allOf(withId(R.id.my_button), withText(“My Button”))) .check(matches(isDisplayed())) .perform(click());!// Une simple extraction de méthode permet de simplifier onView(withIdAndText(R.id.my_button, "My Button”)) .check(matches(isDisplayed())) .perform(click());!// Si le bouton n'est pas affiché le perform(click()) échouera onView(withIdAndText(R.id.my_button, "My Button")).perform(click());

@Tom404_

Page 84: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Exemple

#Droidcon #Robotium #Espresso

onView(allOf(withId(R.id.my_button), withText(“My Button”))) .check(matches(isDisplayed())) .perform(click());

Manque de restrictions = AmbiguousViewMatcherException

!// Une simple extraction de méthode permet de simplifier onView(withIdAndText(R.id.my_button, "My Button”)) .check(matches(isDisplayed())) .perform(click());!// Si le bouton n'est pas affiché le perform(click()) échouera onView(withIdAndText(R.id.my_button, "My Button")).perform(click());

@Tom404_

Page 85: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 86: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Listview

#Droidcon #Robotium #Espresso @Tom404_

Page 87: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Listview

#Droidcon #Robotium #Espresso

// Clic sur item solo.clickOnText("textToFind"); !// Si jamais il y'en a plusieurs -> utilisation d'un index solo.clickOnText("textToFind", 3); !// Ou choisir directement la ligne solo.clickInList(2);

Robotium

@Tom404_

Page 88: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Listview

#Droidcon #Robotium #Espresso

onData(allOf(is(instanceOf(String.class)), is("textToFind"))).perform(click()); !// Ou directement à une position onData(is(instanceOf(String.class))).atPosition(0).perform(click()); !// Possibilité de préciser une listview, utile pour le view pager onData(allOf(is(instanceOf(String.class)), is("textToFind"))) .inAdapterView(withId(R.id.my_list)).perform(click()); !// Interaction avec une vue enfant de la ligne onData(allOf(is(instanceOf(String.class)), is("textToFind"))) .onChildView(withId(R.id.my_child)) .perform(click());

Espresso

@Tom404_

Page 89: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Listview

#Droidcon #Robotium #Espresso

// Type renvoyé par la méthode getItem de l'adapteur public class Item { public String name; public String itemContent; }

Espresso : cas plus complexe

!onData(allOf(is(instanceOf(Item.class)), hasProperty(“name", equalTo(“nameToFind")))) .perform(click());

@Tom404_

Page 90: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Listview

#Droidcon #Robotium #Espresso

public static Matcher<Object> withItemName(final Matcher<String> itemTextMatcher){ return new BoundedMatcher<Object, Item>(Item.class) { @Override public boolean matchesSafely(Item item) { return itemTextMatcher.matches(item.name); } ! @Override public void describeTo(Description description) { description.appendText("with item name: "); itemTextMatcher.describeTo(description); } }; }

Espresso : custom matcher

onData(withItemName(equalTo("nameToFind"))).perform(click());

@Tom404_

Page 91: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 92: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Webview

#Droidcon #Robotium #Espresso

Robotium

@Tom404_

Page 93: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Webview

#Droidcon #Robotium #Espresso

RobotiumPossibilité d’interagir avec les webviews

•solo.getWebElements(by)•solo.clickOnWebElement(by)

@Tom404_

Page 94: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Webview

#Droidcon #Robotium #Espresso

RobotiumPossibilité d’interagir avec les webviews

•solo.getWebElements(by)•solo.clickOnWebElement(by)

Plusieurs types de recherches disponibles•By.id(String id)•By.className(String className)•By.textContent(String textContent)•By.name(String name)

@Tom404_

Page 95: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Webview

#Droidcon #Robotium #Espresso

Espresso

@Tom404_

Page 96: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Webview

#Droidcon #Robotium #Espresso

Espresso

@Tom404_

Page 97: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 98: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Navigation Drawer

#Droidcon #Robotium #Espresso @Tom404_

Page 99: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Navigation Drawer

#Droidcon #Robotium #Espresso

Robotium// Attention l'id du frame layout du menu doit absolument être "left_drawer" solo.setNavigationDrawer(Solo.OPENED); !solo.setNavigationDrawer(Solo.CLOSED);

@Tom404_

Page 100: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Navigation Drawer

#Droidcon #Robotium #Espresso

Robotium// Attention l'id du frame layout du menu doit absolument être "left_drawer" solo.setNavigationDrawer(Solo.OPENED); !solo.setNavigationDrawer(Solo.CLOSED);

EspressoDrawerActions.openDrawer(R.id.drawer_layout); !DrawerActions.closeDrawer(R.id.drawer_layout);

@Tom404_

Page 101: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 102: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Action bar

#Droidcon #Robotium #Espresso @Tom404_

Page 103: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Action bar

#Droidcon #Robotium #Espresso

Robotiumsolo.clickOnActionBarItem(R.id.action_example); !// Cas de l'action bar overflow solo.sendKey(KeyEvent.KEYCODE_MENU); solo.clickOnText("action");

@Tom404_

Page 104: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Action bar

#Droidcon #Robotium #Espresso

Robotiumsolo.clickOnActionBarItem(R.id.action_example); !// Cas de l'action bar overflow solo.sendKey(KeyEvent.KEYCODE_MENU); solo.clickOnText("action");

EspressoonView(withId(R.id_action_example)).perform(click()); !// Cas de l'action bar overflow openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext()); onView(withText("action")).perform(click());

@Tom404_

Page 105: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 106: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Back button & Keyboard

#Droidcon #Robotium #Espresso @Tom404_

Page 107: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Back button & Keyboard

#Droidcon #Robotium #Espresso

Robotiumsolo.goBack(); // solo.goBack() est aussi utilisé pour fermer le clavier

@Tom404_

Page 108: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Back button & Keyboard

#Droidcon #Robotium #Espresso

Robotiumsolo.goBack(); // solo.goBack() est aussi utilisé pour fermer le clavier

EspressoEspresso.pressBack(); Espresso.closeSoftKeyboard();

@Tom404_

Page 109: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 110: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Les messages d’erreur

#Droidcon #Robotium #Espresso @Tom404_

Page 111: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium

!junit.framework.AssertionFailedError: View with id: '1234' is not found! at com.robotium.solo.Solo.getView(Solo.java:2008) at com.robotium.solo.Solo.getView(Solo.java:1988) at fr.droidcon.robotium.vs.espresso.samples.test.robotium.SimpleActionsTest.testClickButton(SimpleActionsTest.java:28)

!// Récupération d’une vue inexistante solo.getView(1234);

Robotium vs Espresso : Get ready to rumble !

Les messages d’erreur

#Droidcon #Robotium #Espresso @Tom404_

Page 112: DroidCon 2014 - Robotium vs espresso_droidcon

com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: is <1234> If the target view is not part of the view hierarchy, you may need to use Espresso.onData to load it from one of the following AdapterViews:android.widget.ListView{426f6f18 VFED.VC. ......ID 0,0-720,1557} - android.widget.ListView{4269c598 V.ED.VC. ........ 48,393-1032,1509 #7f070042 app:id/my_list} !View Hierarchy: +>DecorView{id=-1, visibility=VISIBLE, width=1080, height=1776, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1} | +->ActionBarOverlayLayout{id=16909075, res-name=action_bar_overlay_layout, visibility=VISIBLE, width=1080, height=1776, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3} | +-->FrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=1080, height=1557, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-

Espresso!// Récupération d’une vue inexistante onView(withId(1234));

Robotium vs Espresso : Get ready to rumble !

Les messages d’erreur

#Droidcon #Robotium #Espresso @Tom404_

Page 113: DroidCon 2014 - Robotium vs espresso_droidcon
Page 114: DroidCon 2014 - Robotium vs espresso_droidcon

Enchaînements

Page 115: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 116: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Wait and See

#Droidcon #Robotium #Espresso @Tom404_

Page 117: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Wait and See

#Droidcon #Robotium #Espresso

Robotium repose sur le principe de wait & see•solo.waitForActivity(Class class, int timeout)• solo.waitForCondition(Condition condition, int timeout)• solo.waitForDialogToOpen()

@Tom404_

Page 118: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Wait and See

#Droidcon #Robotium #Espresso

solo.clickOnView(R.id.start_activity_button); !// On attend que la vue apparaisse avant d'agir solo.waitForView(R.id.view_in_new_activity); !solo.clickOnView(R.id.view_in_new_activity);

Robotium repose sur le principe de wait & see•solo.waitForActivity(Class class, int timeout)• solo.waitForCondition(Condition condition, int timeout)• solo.waitForDialogToOpen()

@Tom404_

Page 119: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 120: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso @Tom404_

Page 121: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso

Entrée en jeu du GoogleInstrumentationTestRunner

@Tom404_

Page 122: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso

Entrée en jeu du GoogleInstrumentationTestRunner

Monitoring plus fin des activités et des ressources

@Tom404_

Page 123: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso

Entrée en jeu du GoogleInstrumentationTestRunner

Monitoring plus fin des activités et des ressources

Analyse du ThreadUI pour savoir quand agir

@Tom404_

Page 124: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso

Entrée en jeu du GoogleInstrumentationTestRunner

Monitoring plus fin des activités et des ressources

Analyse du ThreadUI pour savoir quand agir

Pas de wait

@Tom404_

Page 125: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Finis de dormir !

#Droidcon #Robotium #Espresso

onView(withId(R.id.start_activity_button)).perform(click()); !onView(withId(R.id.view_in_new_activity)).perform(click());

Entrée en jeu du GoogleInstrumentationTestRunner

Monitoring plus fin des activités et des ressources

Analyse du ThreadUI pour savoir quand agir

Pas de wait

@Tom404_

Page 126: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso @Tom404_

Page 127: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Idle mais actif !

#Droidcon #Robotium #Espresso @Tom404_

Page 128: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

Idle mais actif !

#Droidcon #Robotium #Espresso

Possibilité d'enregistrer des idlingResources

@Tom404_

Page 129: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso

class EspressoThreadPool extends ThreadPoolExecutor implements IdlingResource { private int threadCount = 0; private ResourceCallback resourceCallback; ... @Override public synchronized void execute(Runnable r) { threadCount++; super.execute(r); } @Override public synchronized boolean isIdleNow() { return threadCount == 0; } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } @Override protected synchronized void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); threadCount--; if (resourceCallback != null && isIdleNow()) { resourceCallback.onTransitionToIdle(); } } }

@Tom404_

Page 130: DroidCon 2014 - Robotium vs espresso_droidcon

Robotium vs Espresso : Get ready to rumble !

#Droidcon #Robotium #Espresso

class EspressoThreadPool extends ThreadPoolExecutor implements IdlingResource { private int threadCount = 0; private ResourceCallback resourceCallback; ... @Override public synchronized void execute(Runnable r) { threadCount++; super.execute(r); } @Override public synchronized boolean isIdleNow() { return threadCount == 0; } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } @Override protected synchronized void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); threadCount--; if (resourceCallback != null && isIdleNow()) { resourceCallback.onTransitionToIdle(); } } }

Espresso.registerIdlingResources(espressoThreadPool);

@Tom404_

Page 131: DroidCon 2014 - Robotium vs espresso_droidcon
Page 132: DroidCon 2014 - Robotium vs espresso_droidcon

Conclusion

Page 133: DroidCon 2014 - Robotium vs espresso_droidcon
Page 134: DroidCon 2014 - Robotium vs espresso_droidcon

Questions ?

Page 135: DroidCon 2014 - Robotium vs espresso_droidcon