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

BABBQ5 - Automated Testing for Modern Android A...

Andy Dyer
October 17, 2014

BABBQ5 - Automated Testing for Modern Android Applications

How to use dependency injection, mocking, and a test runner to automate UI & unit testing. Sample app source on GitHub: https://github.com/abdyer/android-test-demo

Andy Dyer

October 17, 2014
Tweet

More Decks by Andy Dyer

Other Decks in Programming

Transcript

  1. DEPENDENCY INJECTION ▸ Decouples application components ▸ Classes receive dependencies,

    don’t have to know where to find them or how to create them ▸ Makes it easy to swap components for mocks in tests
  2. BASIC DEPENDENCY INJECTION public class Beer { Water water; Barley

    barley; Hops hops; public Beer(Water water, Barley barley, Hops hops) { this.water = water; this.barley = barley; this.hops = hops; } }
  3. DAGGER ▸ Define dependencies at compile time to avoid reflection

    at runtime ▸ Compiler validates modules and injections ▸ Jake Wharton “Architecting Android Applications with Dagger" goo.gl/JIM7KI square.github.io/dagger
  4. DAGGER MODULES @Module(injects = {MyActivity.class, MyFragment.class}) public class MyModule {

    @Provides @Singleton public MyService provideMyService() { return new MyService(); } }
  5. DAGGER OBJECT GRAPH public class MyApplication extends Application { private

    dagger.ObjectGraph objectGraph; @Getter static MyApplication instance; @Override public void onCreate() { super.onCreate(); instance = this; objectGraph = dagger.ObjectGraph.create(new MyModule()); } public void inject(Object dependent) { objectGraph.inject(dependent); } }
  6. DAGGER DEPENDENCY INJECTION public class MyFragment extends Fragment { @Inject

    MyService service; @Override public void onViewCreated(View view, Bundle savedInstanceState) { MyApplication.getInstance().inject(this); service.getMyData(); } }
  7. MOCKING & STUBBING ▸ Substitute runtime implementation for something that

    can be predictably tested in isolation ▸ Verify behavior
  8. MOCKITO ▸ Mock/stub dependencies and function return values ▸ Inject

    mocks to validate behavior in tests ▸ Use included Hamcrest matchers for clear, readable tests code.google.com/p/mockito/
  9. USING MOCKITO MyClass mocked = mock(MyClass.class); // code to inject

    mock & load activity/fragment // ... verify(mocked).getMyData(anyInt(), anyString());
  10. ESPRESSO ▸ Handles activity creation & state sync ▸ Simple,

    concise API ▸ Really fast! code.google.com/p/android-test-kit
  11. USING ESPRESSO public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity> { public MyActivityTest()

    { super(MyActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); getActivity(); // trigger activity launch } public void testInvalidEmailShowsError() { onView(withId(R.id.email)).perform(typeText("abc"), closeSoftKeyboard()); onView(withId(R.id.email_sign_in_button)).perform(click()); onView(withId(R.id.email)).check(matches(withError( getActivity().getString(R.string.error_invalid_email)))); } }
  12. SAMPLE APPLICATION OVERVIEW ▸ Retrofit API with sample requests ▸

    Dagger module ▸ Lombok & Android Studio plugin ▸ Login activity ▸ Activity with list fragment to make API request and display data