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

TDD for Android

Avatar for Alex Zhukovich 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.

Project:
https://github.com/AlexZhukovich/TemperatureConverterTDD

Blog:
http://alexzh.com

Avatar for Alex Zhukovich

Alex Zhukovich

September 14, 2016
Tweet

More Decks by Alex Zhukovich

Other Decks in Technology

Transcript

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

    product; •Tests help improve design code; •Tests check that code works;
  2. 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
  3. 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
  4. Bad vs Good UI tests @Test public void shouldVerifyGravity() {

    View view = ...; assertEquals(Gravity.START, view.getForegroundGravity()); ... } @Test public void shouldVerifyOrderCoffee() { onView(withId(R.id.name_edit)) .perform(typeText("User"), closeSoftKeyboard()); onView(withId(R.id.pay)) .perform(click()); onView(withId(R.id.detail_text)) .check(matches(isDisplayed())); } Don’t Do
  5. 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/
  6. 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(R.id.toolbar)) .check(matches(withToolbarTitle( is (TITLE)))); startsWith endsWith ...
  7. UI test @RunWith(AndroidJUnit4.class) public class TemperatureConverterActivityTest { @Test public void

    shouldVerifyConvertingFromCelsiusToFahrenheit() { onView(withId(R.id.inputView)) .perform(typeText(String.valueOf(CELSIUS_VALUE)), closeSoftKeyboard()); setTemperatureUnit(R.id.inputTemperatureSpinner, CELSIUS_STR); setTemperatureUnit(R.id.outputTemperatureSpinner, FAHRENHEIT_STR); onView(withId(R.id.convertButton)) .perform(click()); onView(withId(R.id.outputView)) .check(matches(isDisplayed())); onView(withId(R.id.outputView)) .check(matches(withText(getOutputString(FAHRENHEIT_VALUE)))); } }
  8. 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()); ... } }
  9. 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)); } }
  10. Testing system stuff • Notifications; • Press hardware buttons; •

    Interacting with any applications. UI Automator
  11. Thank you 1. Getting Started with Testing (Android) https://developer.android.com/training/testing/start/index.html 2.

    Espresso https://google.github.io/android-testing-support-library/docs/espresso/ 3. Ui Automator https://developer.android.com/training/testing/ui-testing/uiautomator-testing.html 4. Robolectric http://robolectric.org/ 5. Project https://github.com/AlexZhukovich/TemperatureConverterTDD 6. Blog http://alexzh.com/ @Alex_Zhukovich