TDD for Android

2b0404a5db1a74f01bf3bf94d142e28c?s=47 Alex Zhukovich
September 14, 2016

TDD for Android

Overview of base principle Test-Driven Development. How to use TDD for Android project. Tips for creating well tested Android projects.




Alex Zhukovich

September 14, 2016


  1. TDD for Android

  2. Why do we test? •Testing ensure the Quality of the

    product; •Tests help improve design code; •Tests check that code works;
  3. Observations • Huge activities / fragments • Hard to add

    a new feature • Hard to test • Many apps tested in manual way • Fragmentation • Slow Android tests • Required device • Robolectric • Espresso • etc
  4. Bad vs Good tests @Test public void test1() { mPresenter.attachView(null);

    mPresenter.convertTemperature(); mPresenter.detachView(); verify(mView, never()).getInputValue(); verify(mView, never()).getFromTemperatureUnit(); verify(mView, never()).getToTemperatureUnit(); verify(mView, never()).setOutputValue(anyDouble()); when(mTemperatureFactory.getTemperatureConverter()) .thenReturn(mConverter); doNothing().when(mConverter).convertData(any(InputData.class)); mPresenter.attachView(mView); mPresenter.convertTemperature(); mPresenter.detachView(); verify(mEventBus).register(any()); verify(mView).displayProgress(); verify(mView, times(1)).getInputValue(); verify(mView, times(1)).getFromTemperatureUnit(); verify(mView, times(1)).getToTemperatureUnit(); verify(mEventBus).unregister(any()); } @Test public void shouldVerifyConvertDataSuccessful () { mPresenter.attachView(mView); mPresenter.convertTemperature(); mPresenter.detachView(); verify(mEventBus).register(any()); ... } @Test public void shouldVerifyConvertDataWithNullView() { mPresenter.attachView(null); mPresenter.convertTemperature(); mPresenter.detachView(); verify(mView, never()).getInputValue(); ... } Don’t Do
  5. Bad vs Good UI tests @Test public void shouldVerifyGravity() {

    View view = ...; assertEquals(Gravity.START, view.getForegroundGravity()); ... } @Test public void shouldVerifyOrderCoffee() { onView(withId( .perform(typeText("User"), closeSoftKeyboard()); onView(withId( .perform(click()); onView(withId( .check(matches(isDisplayed())); } Don’t Do
  6. Value

  7. What is Test Driven Development (TDD) Green Refactor Red

  8. Code separations Android App Core Acceptance tests Unit tests

  9. Model-View-Presenter View Presenter Model

  10. Application overview Web service Local

  11. Application overview Presenter Use case Repository Web service Local

  12. Recommendation for setting up the device / emulator One small

    recommendation for avoiding flakiness is turning off animation on real or virtual devices. • Window animation scale • Transition animation scale • Animator duration scale • Settings / Developer Options/
  13. Hamcrest library

  14. Hamcrest + Espresso public static Matcher<Object> withToolbarTitle(final Matcher<String> textMatcher) {

    return new BoundedMatcher<Object, Toolbar>(Toolbar.class) { @Override public boolean matchesSafely(Toolbar toolbar) { return textMatcher.matches(toolbar.getTitle()); } @Override public void describeTo(Description description) { description.appendText("with toolbar title: ") textMatcher.describeTo(description); } }; } onView(withId( .check(matches(withToolbarTitle( is (TITLE)))); startsWith endsWith ...
  15. UI test @RunWith(AndroidJUnit4.class) public class TemperatureConverterActivityTest { @Test public void

    shouldVerifyConvertingFromCelsiusToFahrenheit() { onView(withId( .perform(typeText(String.valueOf(CELSIUS_VALUE)), closeSoftKeyboard()); setTemperatureUnit(, CELSIUS_STR); setTemperatureUnit(, FAHRENHEIT_STR); onView(withId( .perform(click()); onView(withId( .check(matches(isDisplayed())); onView(withId( .check(matches(withText(getOutputString(FAHRENHEIT_VALUE)))); } }
  16. Presenter test @RunWith(MockitoJUnitRunner.class) public class TemperatureConverterPresenterTest { @Mock TemperatureConverterView mView;

    … private TemperatureConverterPresenter mPresenter; @Test public void shouldVerifyConvertDataSuccessfulWithCorrectView() { mPresenter.attachView(mView); mPresenter.convertTemperature(); mPresenter.detachView(); verify(mEventBus).register(any()); ... } }
  17. Asynchronous calls using Mockito (Retrofit2) @RunWith(MockitoJUnitRunner.class) public class OnlineConverterTemperatureTest {

    private OnlineConverterTemperature mConverter; @Mock EventBus mEventBus; @Mock TemperatureConverterApiService mApiService; @Mock Call<ConvertedResult> mCall; @Mock ResponseBody mResponseBody; @Captor ArgumentCaptor<Callback<ConvertedResult>> argumentCapture; @Test public void shouldGetConvertedResult() { when(mApiService.getConvertedData(anyString(), anyString(), anyString())) .thenReturn(mCall); Response<ConvertedResult> response = Response.success(mConvertedResult); mConverter.convertData(mInputData); verify(mCall).enqueue(argumentCapture.capture()); argumentCapture.getValue().onResponse(null, response); verify(mEventBus).post(new TemperatureConvertedSuccessful(mConvertedResult)); } }
  18. Testing system stuff • Notifications; • Press hardware buttons; •

    Interacting with any applications. UI Automator
  19. Continuous Integration (CIRCLE CI) circle.yml

  20. Testing tips

  21. Focus on App behaviour

  22. Use available stuff

  23. Use hamcrest library

  24. Do not copy your code between tests

  25. Launch directly desire screen

  26. Many small tests are better that big ones

  27. Test your code, not using libraries

  28. Test-Driven Development is NOT a silver bullet

  29. Thank you 1. Getting Started with Testing (Android) 2.

    Espresso 3. Ui Automator 4. Robolectric 5. Project 6. Blog @Alex_Zhukovich