Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Testing 2.0

Android Testing 2.0

Build a toolset to write rock solid apps.

Prateek Srivastava

April 10, 2015
Tweet

More Decks by Prateek Srivastava

Other Decks in Technology

Transcript

  1. public class UtilsTest extends TestCase { public void testIsNullOrEmpty() {

    assertEquals(isNullOrEmpty(null), true); assertEquals(isNullOrEmpty(""), true); assertEquals(isNullOrEmpty(" "), true); assertEquals(isNullOrEmpty("foo"), false); } }
  2. public class UtilsTest { @Test public void isNullOrEmpty() { assertEquals(isNullOrEmpty(null),

    true); assertEquals(isNullOrEmpty(""), true); assertEquals(isNullOrEmpty(" "), true); assertEquals(isNullOrEmpty("foo"), false); } }
  3. public class TextUtils { ... public static boolean isEmpty(CharSequence cs)

    { throw new RuntimeException("Stub!"); } public static int getTrimmedLength(CharSequence cs) { throw new RuntimeException("Stub!"); } }
  4. public class UtilsTest extends TestCase { public void testIsNullOrEmpty() {

    assertEquals(isNullOrEmpty(null), true); assertEquals(isNullOrEmpty(""), true); assertEquals(isNullOrEmpty(" "), true); assertEquals(isNullOrEmpty("foo"), false); } } http://developer.android.com/reference/junit/framework/ TestCase.html
  5. @RunWith(RobolectricTestRunner.class) public class UtilsTest { @Test public void isNullOrEmpty() {

    assertEquals(isNullOrEmpty(null), true); assertEquals(isNullOrEmpty(""), true); assertEquals(isNullOrEmpty(" "), true); assertEquals(isNullOrEmpty("foo"), false); } }
  6. @RunWith(RobolectricTestRunner.class) public class UtilsTest { @Test public void isNullOrEmpty() {

    assertEquals(isNullOrEmpty(null), true); assertEquals(isNullOrEmpty(""), true); assertEquals(isNullOrEmpty(" "), true); assertEquals(isNullOrEmpty("foo"), false); } }
  7. Instrumentation Tests larger scoped, black box testing Espresso, Spoon, Wiremock,

    Oh my! - Michael Bailey https://www.youtube.com/watch?v=-xQCNf_5NNM
  8. public class LoginActivity extends Activity { @InjectView(R.id.username) EditText username; @InjectView(R.id.password)

    EditText password; @OnClick(R.id.login) void onLoginClicked() { boolean hasError = false; if (TextUtils.isEmpty(username.getText())) { username.setError(getString(R.string.required)); hasError = true; } else { username.setError(null); } if (TextUtils.isEmpty(password.getText())) { password.setError(getString(R.string.required)); hasError = true; } else { password.setError(null); } if (!hasError) { Intent intent = new Intent(LoginActivity.this, OrderActivity.class); intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); finish(); } } }
  9. public void testEmptyPassword_ShowsError() { // Make sure the initial state

    does not show any errors. assertEquals(username.getError(), null); assertEquals(password.getError(), null); instrumentation.runOnMainSync(new Runnable() { @Override public void run() { // Type a value into the username and password fields. username.setText("elvis"); password.setText(""); // Click the "login" button. login.performClick(); } }); instrumentation.waitForIdleSync(); // Verify error was shown only for password field. assertEquals(username.getError(), null); assertEquals(password.getError(), getString(R.string.required)); }
  10. public void testEmptyPassword_ShowsError() { // Make sure the initial state

    does not show any errors. assertEquals(username.getError(), null); assertEquals(password.getError(), null); instrumentation.runOnMainSync(new Runnable() { @Override public void run() { // Type a value into the username and password fields. username.setText("elvis"); password.setText(""); // Click the "login" button. login.performClick(); } }); instrumentation.waitForIdleSync(); // Verify error was shown only for password field. assertEquals(username.getError(), null); assertEquals(password.getError(), getString(R.string.required)); }
  11. public void testEmptyPassword_ShowsError() { // Make sure the initial state

    does not show any errors. assertThat(username).hasNoError(); assertThat(password).hasNoError(); // Type a value into the username and password fields. solo.typeText(username, "elvis"); solo.typeText(password, ""); // Click the "login" button. solo.clickOnView(login); // Verify error was shown only for username field. assertThat(username).hasNoError(); assertThat(password).hasError(R.string.required); }
  12. public void testEmptyPassword_ShowsError() { // Make sure the initial state

    does not show any errors. onView(withId(R.id.username)).check(matches(hasNoError())); onView(withId(R.id.password)).check(matches(hasNoError())); // Type a value into the username and password fields. onView(withId(R.id.username)).perform(typeText("elvis")); onView(withId(R.id.password)).perform(typeText("")); // Click the "login" button. onView(withId(R.id.login)).perform(click()); // Verify error was shown only for username field. onView(withId(R.id.password)).check(matches(hasNoError())); onView(withId(R.id.password)) .check(matches(hasError(R.string.required))); } https://code.google.com/p/android-test-kit/wiki/ EspressoV2CheatSheet
  13. public void testEmptyPassword_ShowsError() { Spoon.screenshot(activity, "initial_state"); // Make sure the

    initial state does not show any errors. onView(withId(R.id.username)).check(matches(hasNoError())); onView(withId(R.id.password)).check(matches(hasNoError())); // Type a value into the username and password fields. onView(withId(R.id.username)).perform(typeText("elvis")); onView(withId(R.id.password)).perform(typeText("")); Spoon.screenshot(activity, "typed_text"); // Click the "login" button. onView(withId(R.id.login)).perform(click()); Spoon.screenshot(activity, "login_clicked"); // Verify error was shown only for username field. onView(withId(R.id.password)).check(matches(hasNoError())); onView(withId(R.id.password)) .check(matches(hasError(R.string.required))); }
  14. public void testEmptyPassword_ShowsError() { Spoon.screenshot(activity, "initial_state"); // Make sure the

    initial state does not show any errors. onView(withId(R.id.username)).check(matches(hasNoError())); onView(withId(R.id.password)).check(matches(hasNoError())); // Type a value into the username and password fields. onView(withId(R.id.username)).perform(typeText("elvis")); onView(withId(R.id.password)).perform(typeText("")); Spoon.screenshot(activity, "typed_text"); // Click the "login" button. onView(withId(R.id.login)).perform(click()); Spoon.screenshot(activity, "login_clicked"); // Verify error was shown only for username field. onView(withId(R.id.password)).check(matches(hasNoError())); onView(withId(R.id.password)) .check(matches(hasError(R.string.required))); }
  15. class MixpanelAdapter implements Adapter { final MixpanelAPI.People people; … void

    identify(IdentifyMessage message) { JSONObject json = new JSONObject(); json.put("$email", message.email()); json.put("$first_name", message.firstName()); json.put("$last_name", message.lastName()); people.identify(message.userId()); people.set(json); } }
  16. @Test public void identify() throws JSONException { // 1. Prepare

    our mocks MixpanelAPI.People people = Mockito.mock(MixpanelAPI.People.class); MixpanelAdapter adapter = mockAdapter(people); Analytics analytics = createAnalyticsWithMock(adapter); // 2. Exercise the test analytics.identify("elvis", new Traits() .putFirstName("Elvis") .putLastName("Presley") .putEmail("[email protected]")); JSONObject expected = new JSONObject(); expected.put("userId", "elvis"); expected.put("$email", "[email protected]"); expected.put("$first_name", "Elvis"); expected.put("$last_name", "Presley"); // 3. Verify that we saw what we expected Mockito.verify(people).identify("elvis"); Mockito.verify(people).set(eq(expected)); }
  17. class LocalyticsAdapter implements Adapter { void identify(IdentifyMessage message) { Localytics.setCustomerId(message.userId());

    Localytics.setIdentifier("email", message.email()); Localytics.setIdentifier("customer_name", message.name()); } }
  18. @Test public void identify() { // 1. Prepare mocks. PowerMockito.mockStatic(Localytics.class);

    Analytics analytics = createAnalytics(); // 2. Test the code of interest. analytics.identify("elvis", new Traits() .putFirstName("Elvis") .putLastName("Presley") .putEmail("[email protected]")); // 3. Validate that we saw exactly what we wanted. PowerMockito.verifyStatic(); Localytics.setCustomerId("elvis"); PowerMockito.verifyStatic(); Localytics.setIdentifier("email", "[email protected]"); PowerMockito.verifyStatic(); Localytics.setIdentifier("customer_name", "Elvis Presley"); }
  19. public void test() throws Exception { // Create a MockWebServer.

    MockWebServer server = new MockWebServer(); // Schedule some responses. server.enqueue(new MockResponse().setBody("hello, world!")); // Start the server. server.start(); // Ask the server for its URL. You'll need this to make HTTP requests. URL baseUrl = server.getUrl(“/v1/chat/“); // Exercise your application code, which makes those HTTP requests. // Responses are returned in the same order that they are enqueued. Chat chat = new Chat(baseUrl); chat.loadMore(); assertThat(chat.messages()).containsExactly("hello, world!"); // Confirm that your app made the HTTP requests you were expecting. RecordedRequest request1 = server.takeRequest(); assertEquals("/v1/chat/messages/", request1.getPath()); assertThat(request1.getHeader("Authorization")).isNotNull(); // Shut down the server. server.shutdown(); }
  20. public class MyBenchmark extends Benchmark { public void timeMyOperation(int reps)

    { for (int i = 0; i < reps; i++) { MyClass.myOperation(); } } }