Share
Embed
State of Android Testing Support Library
GDG DevFest Dublin 07/11/2015
Iñaki Villar
November 07, 2015
Transcript
66 slides
-
Android Instrumentation Instrumentation AndroidJunitRunner AndroidJunit4 defaultConfig { applicationId "com.example.devfest" minSdkVersion
10 targetSdkVersion 23 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } androidTestCompile 'com.android.support.test:runner:0.4' -
Android Instrumentation Instrumentation AndroidJunitRunner AndroidJunit4 defaultConfig { applicationId "com.example.devfest" minSdkVersion
10 targetSdkVersion 23 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } androidTestCompile 'com.android.support.test:runner:0.4' -
Rules public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> activityTestRule
= new ActivityTestRule<>(MainActivity.class); @Test public void findViewPerformActionDone() { } } -
Rules public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> activityTestRule
= new ActivityTestRule<>(MainActivity.class); @Test public void findViewPerformActionDone() { } } @Test public void testWithBoundService() { IBinder binder = serviceRule.bindService( new Intent(InstrumentationRegistry.getTargetContext(), MyService.class)); MyService service = ((MyService.LocalBinder) binder).getService(); assertTrue("True wasn't returned", service.doSomethingToReturnTrue()); } @Rule public final ServiceTestRule serviceRule = new ServiceTestRule(); -
Filters @RequiresDevice public void findRequiredDeviceToTest(){ } @SdkSuppress(minSdkVersion = 21) public
void findSomePropertyDevice(){ } -
Filters @RequiresDevice public void findRequiredDeviceToTest(){ } @FlakyTest public void findSomeFlakyTest(){
} @SdkSuppress(minSdkVersion = 21) public void findSomePropertyDevice(){ } -
ViewMatchers Espresso public static Matcher<View> withId(final int id) { return
new TypeSafeMatcher<View>() { Resources resources = null; @Override public void describeTo(Description description) { String idDescription = Integer.toString(id); if (resources != null) { try { idDescription = resources.getResourceName(id); } catch (Resources.NotFoundException e) { // No big deal, will just use the int value. idDescription = String.format("%s (resource name not found)", id); } } description.appendText("with id: " + idDescription); } @Override public boolean matchesSafely(View view) { resources = view.getResources(); return id == view.getId(); } }; } -
ViewMatchers Espresso public static Matcher<View> withId(final int id) { return
new TypeSafeMatcher<View>() { Resources resources = null; @Override public void describeTo(Description description) { String idDescription = Integer.toString(id); if (resources != null) { try { idDescription = resources.getResourceName(id); } catch (Resources.NotFoundException e) { // No big deal, will just use the int value. idDescription = String.format("%s (resource name not found)", id); } } description.appendText("with id: " + idDescription); } @Override public boolean matchesSafely(View view) { resources = view.getResources(); return id == view.getId(); } }; } -
ViewMatchers Espresso public static Matcher<View> withId(final int id) { return
new TypeSafeMatcher<View>() { Resources resources = null; @Override public void describeTo(Description description) { String idDescription = Integer.toString(id); if (resources != null) { try { idDescription = resources.getResourceName(id); } catch (Resources.NotFoundException e) { // No big deal, will just use the int value. idDescription = String.format("%s (resource name not found)", id); } } description.appendText("with id: " + idDescription); } @Override public boolean matchesSafely(View view) { resources = view.getResources(); return id == view.getId(); } }; } -
Espresso androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-idling-resource:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1' androidTestCompile
'com.android.support.test.espresso:espresso-web:2.2.1' -
Espresso androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-idling-resource:2.2.1' androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1' androidTestCompile
'com.android.support.test.espresso:espresso-web:2.2.1' ↳ synchronization with background jobs ↳ DatePicker, RecyclerView, Drawer actions,CountingIdlingResource ↳ intent rules ↳ WebView support -
Espresso Intents IntentsTestRule<T extends Activity> extends ActivityTestRule<T> @Override protected void
afterActivityLaunched() { Intents.init(); super.afterActivityLaunched(); } @Override protected void afterActivityFinished() { super.afterActivityFinished(); Intents.release(); } -
Espresso Intents Intended @Test public void typeNumber_ValidInput_InitiatesCall() { // Types
a phone number into the dialer edit text field and presses the call button. onView(withId(R.id.edit_text_caller_number)) .perform(typeText(VALID_PHONE_NUMBER), closeSoftKeyboard()); onView(withId(R.id.button_call_number)).perform(click()); // Verify that an intent to the dialer was sent with the correct action, phone // number and package. Think of Intents intended API as the equivalent to Mockito's verify. intended(allOf( hasAction(Intent.ACTION_CALL), hasData(INTENT_DATA_PHONE_NUMBER), toPackage(PACKAGE_ANDROID_DIALER))); } -
Espresso Intents Intended @Test public void typeNumber_ValidInput_InitiatesCall() { // Types
a phone number into the dialer edit text field and presses the call button. onView(withId(R.id.edit_text_caller_number)) .perform(typeText(VALID_PHONE_NUMBER), closeSoftKeyboard()); onView(withId(R.id.button_call_number)).perform(click()); // Verify that an intent to the dialer was sent with the correct action, phone // number and package. Think of Intents intended API as the equivalent to Mockito's verify. intended(allOf( hasAction(Intent.ACTION_CALL), hasData(INTENT_DATA_PHONE_NUMBER), toPackage(PACKAGE_ANDROID_DIALER))); } -
Espresso Intents Intended @Test public void typeNumber_ValidInput_InitiatesCall() { // Types
a phone number into the dialer edit text field and presses the call button. onView(withId(R.id.edit_text_caller_number)) .perform(typeText(VALID_PHONE_NUMBER), closeSoftKeyboard()); onView(withId(R.id.button_call_number)).perform(click()); // Verify that an intent to the dialer was sent with the correct action, phone // number and package. Think of Intents intended API as the equivalent to Mockito's verify. intended(allOf( hasAction(Intent.ACTION_CALL), hasData(INTENT_DATA_PHONE_NUMBER), toPackage(PACKAGE_ANDROID_DIALER))); } -
Espresso Intents Intending @Test public void pickContactButton_click_SelectsPhoneNumber() { // Stub
all Intents to ContactsActivity to return VALID_PHONE_NUMBER. Note that the Activity // is never launched and result is stubbed. intending(hasComponent(hasShortClassName(".ContactsActivity"))) .respondWith(new ActivityResult(Activity.RESULT_OK, ContactsActivity.createResultData(VALID_PHONE_NUMBER))); // Click the pick contact button. onView(withId(R.id.button_pick_contact)).perform(click()); // Check that the number is displayed in the UI. onView(withId(R.id.edit_text_caller_number)) .check(matches(withText(VALID_PHONE_NUMBER))); } -
Espresso Intents Intending @Test public void pickContactButton_click_SelectsPhoneNumber() { // Stub
all Intents to ContactsActivity to return VALID_PHONE_NUMBER. Note that the Activity // is never launched and result is stubbed. intending(hasComponent(hasShortClassName(".ContactsActivity"))) .respondWith(new ActivityResult(Activity.RESULT_OK, ContactsActivity.createResultData(VALID_PHONE_NUMBER))); // Click the pick contact button. onView(withId(R.id.button_pick_contact)).perform(click()); // Check that the number is displayed in the UI. onView(withId(R.id.edit_text_caller_number)) .check(matches(withText(VALID_PHONE_NUMBER))); } -
Espresso Intents Intending @Test public void pickContactButton_click_SelectsPhoneNumber() { // Stub
all Intents to ContactsActivity to return VALID_PHONE_NUMBER. Note that the Activity // is never launched and result is stubbed. intending(hasComponent(hasShortClassName(".ContactsActivity"))) .respondWith(new ActivityResult(Activity.RESULT_OK, ContactsActivity.createResultData(VALID_PHONE_NUMBER))); // Click the pick contact button. onView(withId(R.id.button_pick_contact)).perform(click()); // Check that the number is displayed in the UI. onView(withId(R.id.edit_text_caller_number)) .check(matches(withText(VALID_PHONE_NUMBER))); } -
Resources http://chiuki.github.io/advanced-android-espresso Advanced Android Espresso - Chiu-Ki Chan https://www.youtube.com/watch?v=hfoAC9gdC74 https://speakerdeck.com/guardiola31337/elegant-unit-testing-droidcon-spain-2015
Elegant?? Unit Testing - Pablo Guardiola Android unit and instrumentation tests- Lars Vogel http://www.vogella.com/tutorials/AndroidTesting/article.html http://developer.android.com/intl/es/tools/testing-support-library/index.html -
Happy Testing Thanks Jose, Stephan, Nick and Carlos @inyaki_mwc +IñakiVillar
https://developers.google.com/experts/