Test-driven development is an iterative process of writing automated tests that define a feature before development, writing code to pass the tests, and finally refactoring the code to meet project architecture standards. The concept has been an integral part of software development since 1999 and Kent Beck championed it as part of the Agile Manifesto. Companies (such as Pivotal Labs) have made pragmatic use as they successfully developed client applications and internal support tools using this approach. As the world goes mobile, greater emphasis has to be placed on test-driving mobile development as well. Specifically, proper TDD is essential when you consider a platform such as Android, a fragmented and relatively test-hostile environment. This blog will be a highlight into the various testing frameworks available for Android, what’s nice about them and what’s not, and what will work to successfully TDD Android applications, relating it back to the importance of Mobile TDD in general.
There are multiple frameworks for test-driven development on Android. Most of these are built on top of the default Android JUnit testing library, and are useful for post-development testing. Android testing is tedious, but important and beneficial considering the vast, fragmented world of Android.
In current implementations in Pivotal Labs Toronto, we experimented with different testing frameworks on a few applications. This was helpful for the senior Android developers to figure out which framework suits their projects the best. As a result, Robolectric is currently being implemented successfully on certain major Android projects. The developers and QA collaborated to successfully integrate these projects with an internal Jenkins CI server and a Pulse Project Monitor, which ensures collaborative quality control and clean builds on every version control push.
Android TDD Generics
Android testing in general is done using JUnit and InstrumentationTestRunners that are provided by Google by default. These are good for writing Unit Test Cases after application development and prototyping. The class ActivityInstrumentationTestCase2<YourActivityName> provides complete functional testing, whereas the class ActivityUnitTestCase provides isolated unit testing of a single activity. Mocking is by default done using Mock Contexts. However, basic Unit Testing and mocking with the Android Dalvik VM has many speed and performance issues. This does not help the fact that Android is the most fragmented and, as a result, a rather hostile environment for test-driven development .
What about other frameworks?
Android has a handful of other frameworks set up to help developers practice TDD. Some examples include: Espresso and JUnit for on-device functionality testing; Robotium for user scenario testing (i.e. on-device GUI and UI testing); Robolectric for off-device testing ; and Borachio for easy on-device testing using mock objects . There are frameworks that take a more behavioural approach towards testing on Android. These include the Calabash framework, which uses the Cucumber language to write automated UI tests for post development.
Robolectric: An in-depth look
Robolectric was developed and open-sourced with love by Pivotal Labs. It uses the Java programming language to write tests, complementing Android’s default language. The framework provides testable behaviour by intercepting calls to Android classes through “shadow classes” and mocking part of the Android framework (contained in the android.jar file). Robolectric can be combined with build automation tools (Maven), mocking frameworks (Mockito), and dependency injection frameworks (Roboguice) to provide a modular way of testing bulk of the Android SDK functionality (including layouts, services and networking) in a more flexible manner than Google’s default testing framework.
An important feature of Robolectric is that it works without the need for emulation on a device or emulator, which can be slow and cumbersome. Robolectric instead runs your tests directly in the JVM (Java Virtual Machine), and reduces typical test overhead times significantly, thus providing the quick turnaround a developer needs to write tests, write code and then refactor . This also enables the developers to run the Android tests in continuous integration environments without any additional setup.
Having given a highlight for test-driven development on mobile, there do exist a few pros and cons:
1. In general, mobile TDD is extremely beneficial for agile companies. In an environment where developers pair-program for 8 hours a day in relatively large teams, and follow an iterative approach to weekly clean builds, it has proven to be highly useful for Pivotal Labs as a company.
2. Specifically in terms of Android TDD, Robolectric compiles tests and actual Java code, and runs the tests on the JVM. The framework tests your application’s core functionality and code without initial device setup. Provided the developer writes proper tests and makes them pass, he/she can be confident that the application behaves as expected when run on the device.
3. In cases when collaborating teams push changes to their project’s version control state many times a day, it is important to track the sanity of the builds. Android TDD frameworks are easy to integrate with Jenkins or other CI systems, and build states can thus be visually logged in Pulse trackers or internal TDD Dashboards. Robolectric in particular makes this process simpler, as it tests your application on the JVM and CI integration requires no additional setup.
1. In a mobile development world, where projects move fast and clients expect rapid delivery, test-driven development is a time consuming process. Robolectric requires the following to be set up – Maven, Android Studio, an Android SDK deployer (Maven-based), and all global and IDE-specific paths to be set up just the right way. This setup ensures that the project is set up for every pair on the team to run tests and deploy the application as they want. For a developer coming into the project and accessing a workstation not set up for Android/TDD development, this could take up to a day. And in the world of mobile where sprints can be as small as a few weeks, this is a day lost in project ramp-up.
2. The architecture and design patterns and scope of the project may have to be rethought. Developers need to achieve a fine balance between writing sensible tests for a feature, and planning and designing the project architecture that include that feature. It is important to know if the code written to pass tests in specific areas fits in well with the overall project design. An example could be: if a developer is writing network architecture for a retail application where thousands of transactions could be happening every hour, then the code should be architected to ensure scalability, reliability and security, and tests should concentrate on the stability of these broader concepts. But, doing as much TDD as possible can solve this problem – practice makes perfect.
In the end, mobile TDD has its pros and cons, but certain tools like Robolectric reduce testing overhead and allow for easy setup with CI. Experience proves that when developers practice it consistently and in a disciplined manner, the pros outweigh the cons, and definite results are visible in the long-term. TDD methods have thus become the primary approaches for agile companies to ensure effective architecture, requirements and design.