http://fr.droidcon.com/2014/agenda
http://fr.droidcon.com/2014/agenda/detail?title=Robotium+vs+Espresso%3A+Get+ready+to+rumble+!
Ladies and gentlemen, boys and girls. Dans le coin rouge, accusant un poids de 104KB, le plus populaire de tous les frameworks de test: Robotium. Dans le coin bleu, avec un poids de 262KB et le support des équipes Google, celui qu’on qualifie de “new comer” : Espresso. Que le match commence !!
Au programme nous verrons avec du code le fonctionnement de ces bibliothèques, leurs avantages mais aussi leurs inconvénients. Nous y parlerons également de Calabash Android et de UI Automator.
Speaker : Thomas Guerin, Xebia
Thomas Guerin est consultant pour Xebia depuis 2011. Passionné de développement Android et adepte des bonnes pratiques de développement, il s'intéresse de près au déploiement continu sur mobile.
10. Robotium vs Espresso : Get ready to rumble !
Pourquoi ne pas faire de tests ?
#Droidcon #Robotium #Espresso @Tom404_
11. Robotium vs Espresso : Get ready to rumble !
Pourquoi ne pas faire de tests ?
“Mes tests durent des heures !”
#Droidcon #Robotium #Espresso @Tom404_
12. Robotium vs Espresso : Get ready to rumble !
Pourquoi ne pas faire de tests ?
“Mes tests durent des heures !”
“Tester ce n’est pas toujours simple !”
#Droidcon #Robotium #Espresso
@Tom404_
13. Robotium vs Espresso : Get ready to rumble !
Pourquoi ne pas faire de tests ?
“Mes tests durent des heures !”
“Tester ce n’est pas toujours simple !”
“Mes tests échouent aléatoirement !”
#Droidcon #Robotium #Espresso
@Tom404_
14. Robotium vs Espresso : Get ready to rumble !
Pourquoi ne pas faire de tests ?
“Mes tests durent des heures !”
“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é”
#Droidcon #Robotium #Espresso
@Tom404_
15. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
16. Robotium vs Espresso : Get ready to rumble !
Un test doit être…
#Droidcon #Robotium #Espresso @Tom404_
17. Robotium vs Espresso : Get ready to rumble !
Un test doit être…
Simple
#Droidcon #Robotium #Espresso
@Tom404_
18. Robotium vs Espresso : Get ready to rumble !
Un test doit être…
Simple Rapide
#Droidcon #Robotium #Espresso
@Tom404_
19. Robotium vs Espresso : Get ready to rumble !
Un test doit être…
Simple Rapide Fiable
#Droidcon #Robotium #Espresso
@Tom404_
20. Robotium vs Espresso : Get ready to rumble !
Un test doit être…
Simple Rapide Fiable Durable
#Droidcon #Robotium #Espresso
@Tom404_
21. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
22. Robotium vs Espresso : Get ready to rumble !
Un mauvais exemple
#Droidcon #Robotium #Espresso @Tom404_
23. Robotium vs Espresso : Get ready to rumble !
Un mauvais exemple
// 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);
#Droidcon #Robotium #Espresso
@Tom404_
24. Robotium vs Espresso : Get ready to rumble !
Un mauvais exemple
// 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);
#Droidcon #Robotium #Espresso
@Tom404_
25. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
26. Robotium vs Espresso : Get ready to rumble !
Les combattants
#Droidcon #Robotium #Espresso @Tom404_
27. Robotium vs Espresso : Get ready to rumble !
Les combattants
Robotium
#Droidcon #Robotium #Espresso
@Tom404_
28. Robotium vs Espresso : Get ready to rumble !
Les combattants
#Droidcon #Robotium #Espresso
VS
Robotium Espresso
@Tom404_
36. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
37. Robotium vs Espresso : Get ready to rumble !
Test Runner
#Droidcon #Robotium #Espresso @Tom404_
38. Robotium vs Espresso : Get ready to rumble !
Test Runner
Robotium utilise le test runner du sdk
#Droidcon #Robotium #Espresso
@Tom404_
39. Robotium vs Espresso : Get ready to rumble !
Test Runner
Robotium utilise le test runner du sdk
Espresso nécessite un test runner spécifique
#Droidcon #Robotium #Espresso
@Tom404_
40. Robotium vs Espresso : Get ready to rumble !
Test Runner
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"
}
#Droidcon #Robotium #Espresso
@Tom404_
41. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
42. Robotium vs Espresso : Get ready to rumble !
GoogleInstrumentationTestRunner
#Droidcon #Robotium #Espresso @Tom404_
43. Robotium vs Espresso : Get ready to rumble !
GoogleInstrumentationTestRunner
onCreate de l'application finalisée avant le début des tests
#Droidcon #Robotium #Espresso
@Tom404_
44. Robotium vs Espresso : Get ready to rumble !
GoogleInstrumentationTestRunner
onCreate de l'application finalisée avant le début des tests
Instrumentation terminée == activités finies
#Droidcon #Robotium #Espresso
@Tom404_
45. Robotium vs Espresso : Get ready to rumble !
GoogleInstrumentationTestRunner
onCreate de l'application finalisée avant le début des tests
Instrumentation terminée == activités finies
Monitoring des activités plus fiable
#Droidcon #Robotium #Espresso
@Tom404_
46. Robotium vs Espresso : Get ready to rumble !
GoogleInstrumentationTestRunner
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
#Droidcon #Robotium #Espresso
@Tom404_
47. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
48. Robotium vs Espresso : Get ready to rumble !
Initialisation
#Droidcon #Robotium #Espresso @Tom404_
49. Robotium vs Espresso : Get ready to rumble !
Initialisation
Robotium
public 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();
}
}
#Droidcon #Robotium #Espresso
@Tom404_
50. Robotium vs Espresso : Get ready to rumble !
Initialisation
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();
}
}
#Droidcon #Robotium #Espresso
@Tom404_
53. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
54. Robotium vs Espresso : Get ready to rumble !
API overview
Robotium
#Droidcon #Robotium #Espresso
@Tom404_
55. Robotium vs Espresso : Get ready to rumble !
API overview
#Droidcon #Robotium #Espresso
Solo
Robotium
@Tom404_
56. Robotium vs Espresso : Get ready to rumble !
API overview
clickOnActionBarHome()
clickOnButton(int index)
searchText(String text)
pressSoftKeyboardNextButton()
clickOnImageButton(int index)
scrollDownList(int index)
clearEditText(int index)
scrollDown()
clickOnToggleButton(String text)
pressMenuItem(int index)
#Droidcon #Robotium #Espresso
Solo
getView(int viewId)
drag(…)
clickInList(int line, int index)
goBack()
setNavigationDrawer(int status)
clickOnActionBarItem(int id)
getButton(int index)
scrollToBottom() searchEditText(String text)
pressSoftKeyboardSearchButton()
@Tom404_
57. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
58. Robotium vs Espresso : Get ready to rumble !
Exemple
#Droidcon #Robotium #Espresso @Tom404_
59. Robotium vs Espresso : Get ready to rumble !
Exemple
// 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)
#Droidcon #Robotium #Espresso
@Tom404_
60. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
61. Robotium vs Espresso : Get ready to rumble !
Hamcrest
#Droidcon #Robotium #Espresso @Tom404_
62. Robotium vs Espresso : Get ready to rumble !
Hamcrest
Librairie de matchers
#Droidcon #Robotium #Espresso
@Tom404_
63. Robotium vs Espresso : Get ready to rumble !
Hamcrest
Librairie de matchers
assertThat("Hello", equalTo("Hello"))
#Droidcon #Robotium #Espresso
@Tom404_
64. Robotium vs Espresso : Get ready to rumble !
Hamcrest
Librairie de matchers
assertThat("Hello", equalTo("Hello"))
!
// Sucre syntaxique
assertThat(“Hello", is("Hello"))
#Droidcon #Robotium #Espresso
@Tom404_
65. Robotium vs Espresso : Get ready to rumble !
Hamcrest
Librairie de matchers
assertThat("Hello", equalTo("Hello"))
!
// Sucre syntaxique
assertThat(“Hello", is("Hello"))
!
// De nombreux matchers disponibles
allOf not instanceOf hasProperty equalToIgnoringCase
#Droidcon #Robotium #Espresso
@Tom404_
66. Robotium vs Espresso : Get ready to rumble !
Hamcrest
Librairie de matchers
assertThat("Hello", equalTo("Hello"))
!
// Sucre syntaxique
assertThat(“Hello", is("Hello"))
!
// De nombreux matchers disponibles
allOf not instanceOf hasProperty equalToIgnoringCase
Possibilité de composition
#Droidcon #Robotium #Espresso
@Tom404_
67. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
68. Robotium vs Espresso : Get ready to rumble !
Hamcrest custom matcher
#Droidcon #Robotium #Espresso @Tom404_
69. Robotium vs Espresso : Get ready to rumble !
Hamcrest custom matcher
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();
}
!
}
#Droidcon #Robotium #Espresso
@Tom404_
70. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
71. Robotium vs Espresso : Get ready to rumble !
API overview
Espresso
#Droidcon #Robotium #Espresso
@Tom404_
72. Robotium vs Espresso : Get ready to rumble !
API overview
Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
#Droidcon #Robotium #Espresso
@Tom404_
73. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso withId()!
onView(Matcher<View>)!
onData(Matcher<Object>
#Droidcon #Robotium #Espresso
withText(text)!
hasSibling(Matcher<View>)
@Tom404_
74. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
#Droidcon #Robotium #Espresso
withId()!
withText(text)!
hasSibling(Matcher<View>)
ViewActions
click()!
typeText(text)
@Tom404_
75. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
#Droidcon #Robotium #Espresso
withId()!
withText(text)!
hasSibling(Matcher<View>)
ViewActions
click()!
typeText(text)
ViewAssertions
doesNotExist()!
matches(Matcher<View>)
@Tom404_
76. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
ViewInteraction / DataInteraction
perform(ViewAction)!
check(ViewAssertion)
#Droidcon #Robotium #Espresso
withId()!
withText(text)!
hasSibling(Matcher<View>)
ViewActions
click()!
typeText(text)
ViewAssertions
doesNotExist()!
matches(Matcher<View>)
@Tom404_
77. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
ViewInteraction / DataInteraction
perform(ViewAction)!
check(ViewAssertion)
#Droidcon #Robotium #Espresso
withId()!
withText(text)!
hasSibling(Matcher<View>)
ViewActions
click()!
typeText(text)
ViewAssertions
doesNotExist()!
matches(Matcher<View>)
@Tom404_
78. Robotium vs Espresso : Get ready to rumble !
API overview
ViewMatchers Espresso
Espresso
onView(Matcher<View>)!
onData(Matcher<Object>
ViewInteraction / DataInteraction
perform(ViewAction)!
check(ViewAssertion)
#Droidcon #Robotium #Espresso
withId()!
withText(text)!
hasSibling(Matcher<View>)
ViewActions
click()!
typeText(text)
ViewAssertions
doesNotExist()!
matches(Matcher<View>)
@Tom404_
79. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
80. Robotium vs Espresso : Get ready to rumble !
Exemple
#Droidcon #Robotium #Espresso @Tom404_
81. Robotium vs Espresso : Get ready to rumble !
Exemple
onView(allOf(withId(R.id.my_button), withText(“My Button”)))
.check(matches(isDisplayed()))
.perform(click());
#Droidcon #Robotium #Espresso
@Tom404_
82. Robotium vs Espresso : Get ready to rumble !
Exemple
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());
#Droidcon #Robotium #Espresso
@Tom404_
83. Robotium vs Espresso : Get ready to rumble !
Exemple
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());
#Droidcon #Robotium #Espresso
@Tom404_
84. Robotium vs Espresso : Get ready to rumble !
Exemple
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());
Manque de restrictions = AmbiguousViewMatcherException
#Droidcon #Robotium #Espresso
@Tom404_
85. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
86. Robotium vs Espresso : Get ready to rumble !
Listview
#Droidcon #Robotium #Espresso @Tom404_
87. Robotium vs Espresso : Get ready to rumble !
Listview
Robotium
// 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);
#Droidcon #Robotium #Espresso
@Tom404_
88. Robotium vs Espresso : Get ready to rumble !
Listview
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());
#Droidcon #Robotium #Espresso
@Tom404_
89. Robotium vs Espresso : Get ready to rumble !
Listview
Espresso : cas plus complexe
// Type renvoyé par la méthode getItem de l'adapteur
public class Item {
public String name;
public String itemContent;
}
!
onData(allOf(is(instanceOf(Item.class)), hasProperty(“name", equalTo(“nameToFind"))))
.perform(click());
#Droidcon #Robotium #Espresso
@Tom404_
90. Robotium vs Espresso : Get ready to rumble !
Listview
Espresso : custom matcher
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);
}
};
}
onData(withItemName(equalTo("nameToFind"))).perform(click());
#Droidcon #Robotium #Espresso
@Tom404_
91. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
92. Robotium vs Espresso : Get ready to rumble !
Webview
Robotium
#Droidcon #Robotium #Espresso
@Tom404_
93. Robotium vs Espresso : Get ready to rumble !
Webview
Robotium
Possibilité d’interagir avec les webviews
•solo.getWebElements(by)
•solo.clickOnWebElement(by)
#Droidcon #Robotium #Espresso
@Tom404_
94. Robotium vs Espresso : Get ready to rumble !
Webview
Robotium
Possibilité 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)
#Droidcon #Robotium #Espresso
@Tom404_
95. Robotium vs Espresso : Get ready to rumble !
Webview
Espresso
#Droidcon #Robotium #Espresso
@Tom404_
96. Robotium vs Espresso : Get ready to rumble !
Webview
Espresso
#Droidcon #Robotium #Espresso
@Tom404_
97. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
98. Robotium vs Espresso : Get ready to rumble !
Navigation Drawer
#Droidcon #Robotium #Espresso @Tom404_
99. Robotium vs Espresso : Get ready to rumble !
Navigation Drawer
Robotium
// Attention l'id du frame layout du menu doit absolument être "left_drawer"
solo.setNavigationDrawer(Solo.OPENED);
!
solo.setNavigationDrawer(Solo.CLOSED);
#Droidcon #Robotium #Espresso
@Tom404_
100. Robotium vs Espresso : Get ready to rumble !
Navigation Drawer
Robotium
// Attention l'id du frame layout du menu doit absolument être "left_drawer"
solo.setNavigationDrawer(Solo.OPENED);
!
solo.setNavigationDrawer(Solo.CLOSED);
Espresso
DrawerActions.openDrawer(R.id.drawer_layout);
!
DrawerActions.closeDrawer(R.id.drawer_layout);
#Droidcon #Robotium #Espresso
@Tom404_
101. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
102. Robotium vs Espresso : Get ready to rumble !
Action bar
#Droidcon #Robotium #Espresso @Tom404_
103. Robotium vs Espresso : Get ready to rumble !
Action bar
Robotium
solo.clickOnActionBarItem(R.id.action_example);
!
// Cas de l'action bar overflow
solo.sendKey(KeyEvent.KEYCODE_MENU);
solo.clickOnText("action");
#Droidcon #Robotium #Espresso
@Tom404_
104. Robotium vs Espresso : Get ready to rumble !
Action bar
Robotium
solo.clickOnActionBarItem(R.id.action_example);
!
// Cas de l'action bar overflow
solo.sendKey(KeyEvent.KEYCODE_MENU);
solo.clickOnText("action");
Espresso
onView(withId(R.id_action_example)).perform(click());
!
// Cas de l'action bar overflow
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
onView(withText("action")).perform(click());
#Droidcon #Robotium #Espresso
@Tom404_
105. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
106. Robotium vs Espresso : Get ready to rumble !
Back button & Keyboard
#Droidcon #Robotium #Espresso @Tom404_
107. Robotium vs Espresso : Get ready to rumble !
Back button & Keyboard
Robotium
solo.goBack();
// solo.goBack() est aussi utilisé pour fermer le clavier
#Droidcon #Robotium #Espresso
@Tom404_
108. Robotium vs Espresso : Get ready to rumble !
Back button & Keyboard
Robotium
solo.goBack();
// solo.goBack() est aussi utilisé pour fermer le clavier
Espresso
Espresso.pressBack();
Espresso.closeSoftKeyboard();
#Droidcon #Robotium #Espresso
@Tom404_
109. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
110. Robotium vs Espresso : Get ready to rumble !
Les messages d’erreur
#Droidcon #Robotium #Espresso @Tom404_
111. Robotium vs Espresso : Get ready to rumble !
Les messages d’erreur
Robotium
!
// Récupération d’une vue inexistante
solo.getView(1234);
!j
unit.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(SimpleAct
ionsTest.java:28)
#Droidcon #Robotium #Espresso @Tom404_
112. Robotium vs Espresso : Get ready to rumble !
Les messages d’erreur
Espresso
!
// Récupération d’une vue inexistante
onView(withId(1234));
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-
#Droidcon #Robotium #Espresso @Tom404_
115. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
116. Robotium vs Espresso : Get ready to rumble !
Wait and See
#Droidcon #Robotium #Espresso @Tom404_
117. Robotium vs Espresso : Get ready to rumble !
Wait and See
Robotium repose sur le principe de wait & see
•solo.waitForActivity(Class class, int timeout)
• solo.waitForCondition(Condition condition, int timeout)
• solo.waitForDialogToOpen()
#Droidcon #Robotium #Espresso
@Tom404_
118. Robotium vs Espresso : Get ready to rumble !
Wait and See
Robotium repose sur le principe de wait & see
•solo.waitForActivity(Class class, int timeout)
• solo.waitForCondition(Condition condition, int timeout)
• solo.waitForDialogToOpen()
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);
#Droidcon #Robotium #Espresso
@Tom404_
119. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
120. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
#Droidcon #Robotium #Espresso @Tom404_
121. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
Entrée en jeu du GoogleInstrumentationTestRunner
#Droidcon #Robotium #Espresso
@Tom404_
122. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
Entrée en jeu du GoogleInstrumentationTestRunner
Monitoring plus fin des activités et des ressources
#Droidcon #Robotium #Espresso
@Tom404_
123. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
Entrée en jeu du GoogleInstrumentationTestRunner
Monitoring plus fin des activités et des ressources
Analyse du ThreadUI pour savoir quand agir
#Droidcon #Robotium #Espresso
@Tom404_
124. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
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
#Droidcon #Robotium #Espresso
@Tom404_
125. Robotium vs Espresso : Get ready to rumble !
Finis de dormir !
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
onView(withId(R.id.start_activity_button)).perform(click());
!
onView(withId(R.id.view_in_new_activity)).perform(click());
#Droidcon #Robotium #Espresso
@Tom404_
126. Robotium vs Espresso : Get ready to rumble !
#Droidcon #Robotium #Espresso @Tom404_
127. Robotium vs Espresso : Get ready to rumble !
Idle mais actif !
#Droidcon #Robotium #Espresso @Tom404_
128. Robotium vs Espresso : Get ready to rumble !
Idle mais actif !
Possibilité d'enregistrer des idlingResources
#Droidcon #Robotium #Espresso
@Tom404_
129. Robotium vs Espresso : Get ready to rumble !
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();
}
}
}
#Droidcon #Robotium #Espresso
@Tom404_
130. Robotium vs Espresso : Get ready to rumble !
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);
#Droidcon #Robotium #Espresso
@Tom404_