DYNAMIC LANGUAGES
"Tests shouldn't drive implementation."
Slide 10
Slide 10 text
STATIC LANGUAGES
"You know nothing."
Slide 11
Slide 11 text
MAKING ANDROID APPS TESTABLE
▸ Dependency injection
▸ Mocking & stubbing
▸ Unit & integration tests
Slide 12
Slide 12 text
DEPENDENCY INJECTION
Slide 13
Slide 13 text
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
Slide 14
Slide 14 text
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;
}
}
Slide 15
Slide 15 text
DAGGER
A Java dependency injection library
Slide 16
Slide 16 text
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
Slide 17
Slide 17 text
DAGGER MODULES
@Module(injects = {MyActivity.class, MyFragment.class})
public class MyModule {
@Provides @Singleton
public MyService provideMyService() {
return new MyService();
}
}
Slide 18
Slide 18 text
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);
}
}
Slide 19
Slide 19 text
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();
}
}
Slide 20
Slide 20 text
MOCKING & STUBBING
Slide 21
Slide 21 text
MOCKING & STUBBING
▸ Substitute runtime implementation for something that can be
predictably tested in isolation
▸ Verify behavior
Slide 22
Slide 22 text
MOCKITO
A Java mocking library
Slide 23
Slide 23 text
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/
Slide 24
Slide 24 text
USING MOCKITO
MyClass mocked = mock(MyClass.class);
// code to inject mock & load activity/fragment
// ...
verify(mocked).getMyData(anyInt(), anyString());
Slide 25
Slide 25 text
UNIT & INTEGRATION TESTS
Slide 26
Slide 26 text
"Tests or it didn't happen."
Slide 27
Slide 27 text
ESPRESSO
An Android UI test library
Slide 28
Slide 28 text
ESPRESSO
▸ Handles activity creation & state sync
▸ Simple, concise API
▸ Really fast!
code.google.com/p/android-test-kit
Slide 29
Slide 29 text
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))));
}
}
Slide 30
Slide 30 text
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