Slide 1

Slide 1 text

TDD for Android

Slide 2

Slide 2 text

Why do we test? •Testing ensure the Quality of the product; •Tests help improve design code; •Tests check that code works;

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Value

Slide 7

Slide 7 text

What is Test Driven Development (TDD) Green Refactor Red

Slide 8

Slide 8 text

Code separations Android App Core Acceptance tests Unit tests

Slide 9

Slide 9 text

Model-View-Presenter View Presenter Model

Slide 10

Slide 10 text

Application overview Web service Local

Slide 11

Slide 11 text

Application overview Presenter Use case Repository Web service Local

Slide 12

Slide 12 text

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/

Slide 13

Slide 13 text

Hamcrest library

Slide 14

Slide 14 text

Hamcrest + Espresso public static Matcher withToolbarTitle(final Matcher textMatcher) { return new BoundedMatcher(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 ...

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Asynchronous calls using Mockito (Retrofit2) @RunWith(MockitoJUnitRunner.class) public class OnlineConverterTemperatureTest { private OnlineConverterTemperature mConverter; @Mock EventBus mEventBus; @Mock TemperatureConverterApiService mApiService; @Mock Call mCall; @Mock ResponseBody mResponseBody; @Captor ArgumentCaptor> argumentCapture; @Test public void shouldGetConvertedResult() { when(mApiService.getConvertedData(anyString(), anyString(), anyString())) .thenReturn(mCall); Response response = Response.success(mConvertedResult); mConverter.convertData(mInputData); verify(mCall).enqueue(argumentCapture.capture()); argumentCapture.getValue().onResponse(null, response); verify(mEventBus).post(new TemperatureConvertedSuccessful(mConvertedResult)); } }

Slide 18

Slide 18 text

Testing system stuff • Notifications; • Press hardware buttons; • Interacting with any applications. UI Automator

Slide 19

Slide 19 text

Continuous Integration (CIRCLE CI) circle.yml

Slide 20

Slide 20 text

Testing tips

Slide 21

Slide 21 text

Focus on App behaviour

Slide 22

Slide 22 text

Use available stuff

Slide 23

Slide 23 text

Use hamcrest library

Slide 24

Slide 24 text

Do not copy your code between tests

Slide 25

Slide 25 text

Launch directly desire screen

Slide 26

Slide 26 text

Many small tests are better that big ones

Slide 27

Slide 27 text

Test your code, not using libraries

Slide 28

Slide 28 text

Test-Driven Development is NOT a silver bullet

Slide 29

Slide 29 text

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