Tuesday, November 20, 2012

Android Test Driven Development

The unit test is the heart of Test Driven Development (TDD). For the development cycle of TDD to be effective, it is crucial that your unit tests run fast and that the test-deploy-program cycle runs smoothly and does not break your flow when you are "in the zone".

The Android Testing framework that is integrated with the Android Development environment is however not well suited for TDD. Why? Whenever you want to run a test in this environment, the test and the code being tested needs to be deployed on the Android Emulator (or an actual device) where they can be run in an actual Android Runtime Environment (i.e. the Dalvik VM). This deployment is slow (takes several seconds) making the test driven development cycle heavy and cumbersome - which is exactly what it is not supposed to be. To put it short: relying on the Android emulator or an actual device for unit testing is a pain in the butt (the lights in my office dim when I start the emulator).

Dependency inversion and mock objects

If you follow the SOLID principles (which you should (listen to your mother!)) you know that your code should not depend on the actual Android implementations but instead you should wrap and mask these with appropriate interfaces. On runtime you use the android implementations for your interfaces and when unit testing you inject a mock implementation. When mocking the Android methods you can use frameworks like mockito to help you out and eventually you might have your core application code as a pure java library. Now you can unit test this code with the normal JVM and at runtime you provide interface implementations from a separate Android library. This is how I was doing Android TDD until recently.



The downside with this is that you end up with a lot of test-specific code - mocking out all Android dependencies quickly results in a lot of boilerplate code.  So my concern is this:  How can we do TDD with Android and follow the dependency inversion principle but reduce the level of test-specific code?

Introducing Robolectric

Recently I started using Robolectric for all my Android unit tests. This has significantly boosted my work-flow when programming and reduced the level of mocking required in my projects.

Robolectric intercepts the loading of the Android classes and instead provides shadow objects for the corresponding Android classes. This means that you can run your unit tests on a regular Java VM in your IDE test environment. Robolectric integrates very nicely with maven and getting it to work with eclipse is relatively straight forward if you follow the steps on their website.

What about the Android Testing framework then?

Although I avoid using the Android Testing Framework in my TDD work cycle, it is still extremely useful for integration testing.  Integration tests are important tests but they are usually run less frequently and most programmers (well...at least me) don't include them in the daily TDD cycle. In particular the Android Test Framework is needed when you want to run integration tests using an actual device database, network connection, wifi, Bluetooth, NFC etc.