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

BABBQ5 - Automated Testing for Modern Android Applications

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. AUTOMATED TESTING FOR
    Modern ANDROID
    APPLICATIONS

    View Slide

  2. ANDY DYER
    +AndrewDyer || @dammitandy

    View Slide

  3. View Slide

  4. MUSIC LIBRARY

    View Slide

  5. WRIST PRESENTER

    View Slide

  6. RECORDS,
    COFFEE & BEER

    View Slide

  7. "Ich lerne Deutsch."

    View Slide

  8. MAKING ANDROID APPS TESTABLE

    View Slide

  9. DYNAMIC LANGUAGES
    "Tests shouldn't drive implementation."

    View Slide

  10. STATIC LANGUAGES
    "You know nothing."

    View Slide

  11. MAKING ANDROID APPS TESTABLE
    ▸ Dependency injection
    ▸ Mocking & stubbing
    ▸ Unit & integration tests

    View Slide

  12. DEPENDENCY INJECTION

    View Slide

  13. 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

    View Slide

  14. 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;
    }
    }

    View Slide

  15. DAGGER
    A Java dependency injection library

    View Slide

  16. 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

    View Slide

  17. DAGGER MODULES
    @Module(injects = {MyActivity.class, MyFragment.class})
    public class MyModule {
    @Provides @Singleton
    public MyService provideMyService() {
    return new MyService();
    }
    }

    View Slide

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

    View Slide

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

    View Slide

  20. MOCKING & STUBBING

    View Slide

  21. MOCKING & STUBBING
    ▸ Substitute runtime implementation for something that can be
    predictably tested in isolation
    ▸ Verify behavior

    View Slide

  22. MOCKITO
    A Java mocking library

    View Slide

  23. 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/

    View Slide

  24. USING MOCKITO
    MyClass mocked = mock(MyClass.class);
    // code to inject mock & load activity/fragment
    // ...
    verify(mocked).getMyData(anyInt(), anyString());

    View Slide

  25. UNIT & INTEGRATION TESTS

    View Slide

  26. "Tests or it didn't happen."

    View Slide

  27. ESPRESSO
    An Android UI test library

    View Slide

  28. ESPRESSO
    ▸ Handles activity creation & state sync
    ▸ Simple, concise API
    ▸ Really fast!
    code.google.com/p/android-test-kit

    View Slide

  29. USING ESPRESSO
    public class MyActivityTest extends ActivityInstrumentationTestCase2 {
    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))));
    }
    }

    View Slide

  30. 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

    View Slide

  31. HABEN SIE FRAGEN?

    View Slide

  32. CODE & SLIDES
    github.com/abdyer/android-test-demo

    View Slide