Building testable WP7 apps using Microsoft.Practices.Phone.Adapters
I’m a big believer in Test Driven Development as an effective practice that helps me write high quality, maintainable code. TDD is a practice I not only apply on larger enterprise applications, but something I try to do even on smaller mobile apps. In the day of the Apple App Store or Microsoft Marketplace you are relying on Apple or Microsoft to approve your application before it’s made available to your users. The process typically takes around a week – meaning it can potentially take a week before you fix a bug and the update is made available to the users. Introducing a bug in your mobile app can greatly hurt your rating in the Marketplace/App Store. Given the fact that you cannot simply upload a quick fix to the app stores, like you can on a web application, having solid testing for mobile applications is even more important than for other types of applications.
With this in mind I was thrilled to see that Microsoft Pattern & Practices had taken this to hearth in their latest guidance for building Windows Phone 7 applications. The latest guide includes three major topics:
- Developing a Windows Phone Application using the MVVM Pattern
- Developing an Advanced Windows Phone 7.5 App that Connects to the Cloud
- Building Testable Windows Phone Applications
I have previously written several blog posts and given presentations on how the MVVM Pattern can help you separate the state and behavior of a piece of UI from the actual View-code. By moving state and behavior into a View Model-class with no UI dependencies, you can easily unit test the View Model in separation. If you would like to learn more about the MVVM-pattern I would strongly recommend my presentation from NDC 2009, or the MVVM-chapter from the P&P WP7 Guidelines. To ensure that the View Model classes can be tested independently it is important that they do not have any external dependencies that are hard to test. Whenever a View Model depends on some external resource, such as a web service, we introduce an interface for that dependency, and enable some form of Dependency Injection on the View Model so that we can replace the dependency with a stub or a mock during test.
When working against the Windows Phone 7 APIs you will quickly realize that they are not very test-friendly. The API consists of several static or sealed classes that provide access to core phone-functionality such as Location Services, Compass, Camera, Gyroscope or other sensors. Since the classes are sealed, and do not implement an interface, there is no simple way to test code accessing these classes directly. The solution in such cases is typically to define your own interface mimicking the underlying API, and then implement an Adapter class delegating through to the underlying API.
To demonstrate this principle I have created a simple application that displays your current location and compass heading. Such an application would need to use two classes that are hard to test; the GeoCoordinateWatcher-class and the Compass-class. A simple design, using the View Model pattern, would look something like this:
The problem with this design is how the TrackingViewModel-class is using the Compass-class and GeoCoordinateWatcher-class directly. It would be impossible to unit test the View Model, both because the Compass-sensor is not available in the simulator, but also just because of the fact that getting a location/compass reading takes time, and would make the tests slow and unreliable. Instead we are going to modify the design, and use the abstractions introduced by the Patterns & Practices team. We change our TrackingViewModel-class to depend on ICompass and IGeoCoordinateWatcher. At test-time we pass in mock-implementations of these two classes to enable testability, while at run-time we use the adapter classes GeoCordinateWatcherAdapter and CompassAdapter.
With this small change we can now write unit tests for the TrackingViewModel-class. Here is an example of some of the tests I have written for the View Model.
Many people assume that you have to use an IoC-container to use Dependency Injection. That is not the case. My personal preference is to not introduce an IoC-container until it is necessary, and instead use overloaded constructors. The TrackingViewModel-class has two constructors, one that accepts the ICompass and IGeoCoordinateWatcher interfaces as parameters, and one default constructor that calls the parameterized constructor passing in the adapter classes as default. This enables testability, yet at the same time keeps the architecture of the application simple.
In this example I only use two of the wrapped classes provided by the Microsoft.Practices.Phone.Adapters project. In addition the project contains adapters for the following classes in the Windows Phone 7.1 SDK:
The Microsoft.Practices.Phone.Adapters project can be added as a NuGet-package. The package adds the interfaces/adapter files to your project, and you can choose to delete the once you don’t need (it is not a pre-compiled package). If you download the example project from the MSDN site you also get a set of pre-written mock-classes you can use in your Unit Test project to mock the different interfaces.
If you want to learn more about making your WP7 applications testable I would strongly encourage you to read the full guide on this on MSDN. As I mentioned in the introduction, testability is just one aspect of the Patterns & Practices Guide for WP7, and I will be covering other areas in a later blog post.
The example application for this blog post is available at https://github.com/follesoe/TestableGeoTrackerDemo.