testing android apps with espresso

34
Testing Android Apps with Espresso

Upload: edipo-souza

Post on 16-Apr-2017

8.001 views

Category:

Presentations & Public Speaking


5 download

TRANSCRIPT

Page 1: Testing android apps with espresso

Testing Android Apps with Espresso

Page 2: Testing android apps with espresso

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.

Page 3: Testing android apps with espresso

● 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

Page 4: Testing android apps with espresso

● “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?

Page 5: Testing android apps with espresso

● “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?

Page 6: Testing android apps with espresso

● Add these lines in your biuld.gradle file

ConfigurationdefaultConfig { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}packagingOptions { exclude 'NOTICE.txt' exclude 'LICENSE.txt'}

Page 7: Testing android apps with espresso

● Add these dependencies in your biuld.gradle file

Configurationdependencies { 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' }}

Page 8: Testing android apps with espresso

● 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

Page 9: Testing android apps with espresso

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() {

}

}

Page 10: Testing android apps with espresso

Main ComponentsMatcher - 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.

Page 11: Testing android apps with espresso

ViewMatcherMatcher Categories

● User PropertiesCommun component attributes

● UI PropertiesCommun UI component state

● ObjectGroup, Logic and Text helpers

● HierarchyIdentifiers based on relationship

● InputType support

● ClassIdentifiers based on object class

● RootWindow holding view object

Page 12: Testing android apps with espresso

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))

}

}

Page 13: Testing android apps with espresso

Action Categories

● Click/PressCommun tap actions

● GesturesSwipe and Scroll actions

● TextEditable actions

ViewActions

Page 14: Testing android apps with espresso

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())

}

}

Page 15: Testing android apps with espresso

Assertions Categories

● GenericHelpers assertions

● LayoutOverlay relationship

● PositionsView positions relationship

ViewAssertions

Page 16: Testing android apps with espresso

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());

Page 17: Testing android apps with espresso

Espresso Cheat Sheet

Page 18: Testing android apps with espresso

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

@AfterThis method is executed after each test method

@BeforeClasspublic static void setUp() { ...}

@Beforepublic static void setupForEachTest() {...}

@Testpublic void test1() {...}

@Testpublic void test2() {…}

@Afterpublic static void undoSetupForEachTest() {…}

@AfterClasspublic static void undoSetup() {…}

Page 19: Testing android apps with espresso

● Espresso-ContribContains Actions to RecyclerView and system components like Pickers

● Espresso-IntentsAllows to Check or Mock response of started intents

● Espresso-Idling-ResourceEnable to define new resources to Espresso wait before proceed

● UI AutomatorLet you do BlackBox test actions on system and third party apps

Extra Libraries

Page 20: Testing android apps with espresso

DrawerActions○ openDrawer(int drawerLayoutId)○ closeDrawer(int drawerLayoutId)

Espresso-ContribDrawerMatches

○ isOpen()○ isClosed()

Page 21: Testing android apps with espresso

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)

Page 22: Testing android apps with espresso

PickerActions

Needed for interact with DatePicker and TimerPicker

Espresso-Contrib

TimePicker○ setTime(int hours, int minutes)

DatePicker○ setDate(int year, int monthOfYear, int dayOfMonth)

Page 23: Testing android apps with espresso

❖ 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

Page 24: Testing android apps with espresso

“ 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

Page 25: Testing android apps with espresso

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 {

@Testpublic 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());

Page 26: Testing android apps with espresso

“ UI Automator is well-suited for writing black box-style automated tests”

UI Automator Viewer

Page 27: Testing android apps with espresso

DEMO

I want Espresso in Action!

Page 28: Testing android apps with espresso

● 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 classactivityRule.getActivity().getApplicationContext();

Activity

InstrumentationRegistry.getContext();

@Rule

public ActivityTestRule<MyActivity> activityRule = new ActivityTestRule<>(MyActivity.class);

activityRule.getActivity().getContext();

withText(R.string.test)

Page 29: Testing android apps with espresso

● 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();

@Testpublic 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

}

Page 30: Testing android apps with espresso

● 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 spinneronView(withId(R.id.spinnerCountries)).perform(click());//Select the country Brazil and clicks in itonData(allOf(is(instanceOf(String.class)), is(“Brazil”))).inRoot(isPlatformPopup()).perform(click());

//Click TAB1onView(withText(“TAB1”)).perform(click());

Page 31: Testing android apps with espresso

● 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 RecyclerViewonView(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));

Page 32: Testing android apps with espresso

● 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 decorViewView 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());

Page 33: Testing android apps with espresso

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?

Page 34: Testing android apps with espresso

[email protected]

www.ediposouza.com

THANKS!!!