This document discusses how to write testable Android apps. It recommends abstracting away from Android APIs to isolate business logic, using dependency injection with Dagger 2, and mocking dependencies for testing. The key points are:
1) Abstract business logic from Android components like Activities and Fragments into plain Java classes like presenters and managers to make logic independently testable.
2) Use dependency injection, preferably with Dagger 2, to avoid direct instantiation with "new" and allow mocking dependencies.
3) For testing, mock dependencies using libraries like Mockito and program to interfaces to make mocking possible. This allows testing presenters and other classes in isolation.
4) Other best practices discussed
11. Android APIs
• difficult to test and mock
• we don’t have creation of Android components
under control
12. Abstracting Android APIs
• we need some boilerplate to get away
• remove all business logic from Android component
classes
• isolate business logic into presenters, managers,
POJOs, …
• when possible use MVP pattern
14. Clean code
• try to write clean code
• avoid methods having hundreds of lines
• avoid Activities/Fragments having thousands of
lines
15. And how to test it?
• our presenters, POJOs, managers, providers, etc.
are simple to test
• Android components are stripped off of business
logic
• nothing important to test remains there
23. Dagger 2
• Field injection
public class MainActivity extends AppCompatActivity {
@Inject ProviderA mProviderA;
@Inject ProviderB mProviderB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApp) getApplication()).getAppComponent()
.injectMainActivity(this);
}
}
24. Dagger 2
• prefer constructor injection wherever possible
• you can test the unit in isolation
• providing mocks is a piece of cake
25. Dagger 2
• Some catches when using field injection
• Construct the whole component
• Implicit provisions doesn’t support overrides!!
public class ProviderA {
…
@Inject
public ProviderA(ProviderC providerC) {
mProviderC = providerC;
}
}
26. Dagger 2
• Some catches when using field injection
• Make explicit provisions
@Module
public class AppModule {
@Provides @Singleton
ProviderB provideProvider2(ProviderC providerC) {
return new ProviderB(providerC);
}
@Provides
ProviderD provideProvider4() {
return new ProviderD();
}
}
• Beware marking constructors with @Inject when providing explicitly
• may create unwanted double provision
34. Static methods
• avoid it as much as possible
• things like TextUtils.isEmpty() can be painful
• alternatives, e.g. Apache commons
StringUtils.isEmpty()
• PowerMock to the rescue
• still better to avoid static
36. Negatives?
• increase the number of methods and classes
• duplication of Android interfaces/classes
• bloated constructors with lots of dependencies