Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Testing android apps with espresso

Presentation about android tests with google espresso taken on 19/09/2015.

  • Login to see the comments

Testing android apps with espresso

  1. 1. Testing Android Apps with Espresso
  2. 2. About me Édipo Souza Édipo Souza has over 3 years experience in android development with Degree in Sistemas e Mídias Digitais by Federal University of Ceará (UFC) and Specialization in Desenvolvimento de Sistemas para Dispositivos Móveis by Faculdade Sete de Setembro (FA7). He has certifications Oracle Certified Associate Java SE 8 Programmer and Programming in HTML5 with JavaScript and CSS3 Specialist.
  3. 3. ● What’s Espresso? ● Why use Espresso? ● Configuration ● Android Test Rules ● Main Components ● Espresso Cheat Sheet ● JUnit Annotations ● Extra Libraries ○ Espresso-Contrib ○ Espresso-Intents ○ UI Automator ● Development Tips ● Commun Situations and Solution Schedule
  4. 4. ● “A simple API for writing reliable UI tests” - Google ● Backward Compatibility Api 8 (Froyo) or Higher ● Open Source - https://code.google.com/p/android-test-kit ● Google Product - Presented at Google Test Automation Conference 2013 ● Android Tool - Added to Android Testing Support Library in 2015 with Version 2.1 released on 2015/04/21 ● Actual version 2.2 What’s Espresso?
  5. 5. ● “The core API is small, predictable, and easy to learn and yet remains open for customization” - Google ● Easy - “An extensive set of action APIs to automate UI interactions.” ● Extensible - “Flexible APIs for view and adapter matching in target apps.” ● Fast - “UI thread synchronization to improve test reliability.” ● No WaitFor(), No Sleep()! ● JUnit4 Support. Why use Espresso?
  6. 6. ● Add these lines in your biuld.gradle file Configuration defaultConfig { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } packagingOptions { exclude 'NOTICE.txt' exclude 'LICENSE.txt' }
  7. 7. ● Add these dependencies in your biuld.gradle file Configuration dependencies { androidTestCompile ('com.android.support.test.espresso:espresso-core:2.2'){exclude module: 'support-annotations'} androidTestCompile ('com.android.support.test.espresso:espresso-intents:2.2'){exclude module: 'support-annotations'} androidTestCompile ('com.android.support.test:runner:0.3'){exclude module: 'support- annotations'} androidTestCompile ('com.android.support.test:rules:0.3'){exclude module: 'support- annotations'} //Optional for uiAutomator androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1' //Optional for RecyclerView androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'support-annotations' exclude module: 'recyclerview-v7' } }
  8. 8. ● Make use of JUnit4 @Rule annotation ● Extends ActivityInstrumentationTestCase2 or ServiceTestCase are deprecated ● ActivityTestRule The activity under the Rule will be launched again in each Test @Rule public ActivityTestRule<MyActivity> activityRule = new ActivityTestRule<>(MyActivity.class); ● ServiceTestRule The service will start and shutdown in each Test using startService it method @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule(); Android Test Rules
  9. 9. OK, show me Code! import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) public class MyActivityTest { @Rule public ActivityTestRule<MyActivity> mActivityRule = new ActivityTestRule<>(MyActivity.class); @Test public void testClickOKButtonAnd() { } }
  10. 10. Main Components Matcher - Provide a way to find a view instance on view hierarchy that matches a given criteria. ViewAction - Provide instructions to perform an Action on view object. ViewAssertion - Allows to check if some view object state matches with given criteria. This can make the Test fail.
  11. 11. ViewMatcher Matcher Categories ● User Properties Commun component attributes ● UI Properties Commun UI component state ● Object Group, Logic and Text helpers ● Hierarchy Identifiers based on relationship ● Input Type support ● Class Identifiers based on object class ● Root Window holding view object
  12. 12. Let’s see it on Code! import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) public class MyActivityTest { @Rule public ActivityTestRule<MyActivity> mActivityRule = new ActivityTestRule<>(MyActivity.class); @Test public void testClickOKButtonAnd() { //Find a button with text 'play' onView(withText(R.string.play)) } }
  13. 13. Action Categories ● Click/Press Commun tap actions ● Gestures Swipe and Scroll actions ● Text Editable actions ViewActions
  14. 14. Cool, but and the Code? import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) public class MyActivityTest { @Rule public ActivityTestRule<MyActivity> mActivityRule = new ActivityTestRule<>(MyActivity.class); @Test public void testClickOKButtonAnd() { //Click on button with text 'play' onView(withText(R.string.play)).perform(click()) } }
  15. 15. Assertions Categories ● Generic Helpers assertions ● Layout Overlay relationship ● Positions View positions relationship ViewAssertions
  16. 16. OK, but I want see Code! import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) public class MyActivityTest { @Rule public ActivityTestRule<MyActivity> mActivityRule = new ActivityTestRule<>(MyActivity.class); @Test public void testClickOKButtonAnd() { //Click on button with text 'play' and Check if text change to 'stop' onView(withText(R.string.play)).perform(click()).check(matches(withText(R.string.stop))); } } //Click on button with text 'play'. Check if view with id btPlayStop has text 'stop' onView(withText(R.string.play)).perform(click()); onView(withId(R.id.btPlayStop)).check(matches(withText(R.string.stop))); //Click on item with text 'Track 3’ in a list of strings. onData(allOf(is(instanceOf(String.class)), is("Track 3"))).perform(click());
  17. 17. Espresso Cheat Sheet
  18. 18. Junit Annotations @BeforeClass The method is executed before all test methods @Before This method is executed before each test method @AfterClass This method is executed after all test methods @After This method is executed after each test method @BeforeClass public static void setUp() { ... } @Before public static void setupForEachTest() { ... } @Test public void test1() { ... } @Test public void test2() { … } @After public static void undoSetupForEachTest() { … } @AfterClass public static void undoSetup() { … }
  19. 19. ● Espresso-Contrib Contains Actions to RecyclerView and system components like Pickers ● Espresso-Intents Allows to Check or Mock response of started intents ● Espresso-Idling-Resource Enable to define new resources to Espresso wait before proceed ● UI Automator Let you do BlackBox test actions on system and third party apps Extra Libraries
  20. 20. DrawerActions ○ openDrawer(int drawerLayoutId) ○ closeDrawer(int drawerLayoutId) Espresso-Contrib DrawerMatches ○ isOpen() ○ isClosed()
  21. 21. RecyclerViewActions Needed because recyclerView extends ViewGroup, not AdapterView, so no onData for it. Espresso-Contrib Actions ○ actionOnHolderItem(Matcher<VH> viewHolderMatcher, ViewAction viewAction) ○ actionOnItem(Matcher<View> itemViewMatcher, ViewAction viewAction) ○ actionOnItemAtPosition(int position, ViewAction viewAction) Scroll ○ scrollTo(Matcher<View> itemViewMatcher) ○ scrollToHolder(Matcher<VH> viewHolderMatcher) ○ scrollToPosition(int position)
  22. 22. PickerActions Needed for interact with DatePicker and TimerPicker Espresso-Contrib TimePicker ○ setTime(int hours, int minutes) DatePicker ○ setDate(int year, int monthOfYear, int dayOfMonth)
  23. 23. ❖ intended(intentMatcher) Allows validation of Intents sent out by the application under test. Espresso-Intents ❖ intending(intentMatcher) .respondWith(activityResult) Enables stubbing the response of Intents sent by startActivityForResult “It’s like Mockito, but for android intents.” Matcher Categories ● Intent Commun intent parameters ● URI URI attributes validations ● Component Name Component class and package validations ● Bundle Search intent based on Entry, Key or Value
  24. 24. “ UI Automator is well-suited for writing black box-style automated tests” UI Automator UIDevice UISelector ○ findObject(UiSelector selector) ○ findObjects(BySelector selector) ○ takeScreenshot(File storePath) ○ pressHome() / Back / Menu / RecentApps ○ pressEnder() / Search / KeyCode(int keyCode) ○ click(int x, int y) ○ swipe(int initX, int initY, int endX, int endY, int steps) ○ openNotification() ○ openQuickSettings() ○ setOrientationLeft() / Right() / Natural() ○ sleep() / wakeUp() / isScreenOn() ○ checked(boolean val) ○ focusable(boolean val) ○ className(Class<T> type) ○ description(String desc) ○ resourceId(String id) ○ text(String text) ○ click() / AndWaitForNewWindow() ○ exists() ○ getText() / setText(String text) / clearTextField() ○ swipeUp(int steps) Down/Left/Right UIObject
  25. 25. Cool, I want see it on Code! import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiSelector; @RunWith(AndroidJUnit4.class) public class MyActivityTest { @Test public void openMemoAndAddANewNote() throws Exception { UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); } } //Go to launcher home uiDevice.pressHome(); //click apps button to open apps drawer uiDevice.findObject(new UiSelector().description("Apps")).clickAndWaitForNewWindow(); //open calculator uiDevice.findObject(new UiSelector().text("Calculator")).clickAndWaitForNewWindow(); //Calculate 3*9 uiDevice.findObject(new UiSelector().description("3")).click(); uiDevice.findObject(new UiSelector().description("Multiply")).click(); uiDevice.findObject(new UiSelector().description("9")).click(); uiDevice.findObject(new UiSelector().description("equal")).click(); //create a selector for result display text based on its resourceId UiSelector resultSelector = new UiSelector().resourceId("com.android.calculator2:id/display_Res_Text"); //check result assertEquals("equal 27", uiDevice.findObject(resultSelector).getText());
  26. 26. “ UI Automator is well-suited for writing black box-style automated tests” UI Automator Viewer
  27. 27. DEMO I want Espresso in Action!
  28. 28. ● Get the application context ● Get the test application context ● Obtain the context of activity to be tested ● The withText() method can be used with a string resource id Development Tips InstrumentationRegistry.getTargetContext(); Test class activityRule.getActivity().getApplicationContext(); Activity InstrumentationRegistry.getContext(); @Rule public ActivityTestRule<MyActivity> activityRule = new ActivityTestRule<>(MyActivity.class); activityRule.getActivity().getContext(); withText(R.string.test)
  29. 29. ● When is expected that the test returns an exception, simply add the expected exception to Test annotation: ● However for large testing is recommended to use use ExpectedException Rule Development Tips @Test(expected = IndexOutOfBoundsException.class) public void test1() { } @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void shouldTestExceptionMessage() throws IndexOutOfBoundsException { List<Object> list = new ArrayList<Object>(); thrown.expect(IndexOutOfBoundsException.class); thrown.expectMessage("Index: 0, Size: 0"); list.get(0); // execution will never get past this line }
  30. 30. ● To interact with the items from Spinner, PopupMenu or similar use: '.inRoot(isPlatformPopup())' ● Stay tuned when performs swipe in a pageView to find an item in list. Perform a click in a tab for that the items can be found Commun Situations/Solution //Clicks in spinner onView(withId(R.id.spinnerCountries)).perform(click()); //Select the country Brazil and clicks in it onData(allOf(is(instanceOf(String.class)), is(“Brazil”))).inRoot(isPlatformPopup()).perform(click()); //Click TAB1 onView(withText(“TAB1”)).perform(click());
  31. 31. ● As RecyclerView extends ViewGroup should be used the onView method to find items in list instead of onData ● If a RecyclerView item is not visible, unlike the ListView, a scroll must be made to the item using RecyclerViewActions.scrollTo() before interacting with the item. Commun Situations/Solution // Perform a click on first element in the RecyclerView onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); Object rvTag = 0; Matcher<View> viewMatcher = hasDescendant(withText(“Item 100”)); onView(withTagValue(is(rvTag))).perform(RecyclerViewActions.scrollTo(viewMatcher));
  32. 32. ● To check whether a toast was displayed ● To perform an action conditionally, we can override the method withFailureHandler, then if the check fails, instead of finishing the test, the method handle is called Commun Situations/Solution //Get the decorView View activityDecorView = mActivityRule.getActivity().getWindow().getDecorView(); onView(withText(TOAST_TEXT)).inRoot(withDecorView(not(activityDecorView))).check(isDisplayed()); onView(withText(R.string.dialog_config_app)).withFailureHandler(new FailureHandler() { @Override public void handle(Throwable throwable, Matcher<View> matcher) { onView(withText(android.R.string.ok)).perform(click()); } }).check(doesNotExist());
  33. 33. Cool Links: ● https://code.google.com/p/android-test-kit/ ● https://github.com/vgrec/EspressoExamples/ ● http://www.vogella.com/tutorials/Mockito/article.html ● https://github.com/junit-team/junit/wiki/Exception-testing ● https://developer.android.com/tools/testing-support-library/index.html ● https://github.com/googlesamples/android-testing/tree/master/espresso ● https://androidresearch.wordpress.com/2015/04/04/an-introduction-to-espresso Questions?
  34. 34. Contact edipo2s@gmail.com www.ediposouza.com THANKS!!!

×