A practical approach to building and unit testing Windows Phone 7 apps
The Model-View-ViewModel (MVVM) architecture pattern has grown increasingly popular in the past few years, particularly in the XAML world of Windows Presentation Foundation (WPF) and Silverlight. This pattern encourages loosely coupled design, which provides numerous benefits, such as ease of maintenance and automated unit testing. The MVVM Light framework provides a core set of MVVM functionality that enhances the Windows Phone 7 development experience with the tools to produce stable and reliable applications quickly and efficiently. Here I'll demonstrate how to leverage the MVVM Light framework to develop maintainable Model-View-ViewModel–based Windows Phone 7 applications with quality backed by an extensive suite of unit tests.
Loosely Coupled Applications
Coupling describes how dependent one component is on another. When two or more components are intimately aware of one another, they are considered very tightly coupled. Though tight coupling produces source code that is very easy to read, it also produces components that are resistant to change because when one of these components changes, it is likely that other components with intimate knowledge of the changed component must be changed as well. With this approach, small changes can snowball into major, system-wide modifications. As the size of prospective changes grows, so does the risk associated with making those changes, as well as anxiety of the developers and managers responsible for the application's stability. Additionally, it is much more difficult to create focused unit tests for tightly coupled applications because components with dependencies that are not easily substituted cannot be tested in isolation. In other words, if a test fails, it is often very difficult to determine which component contains the faulty logic because so many components may be involved.
Software architecture that encourages loose coupling helps ease these pains by providing interchangeable components that are much easier to isolate. With proper isolation, unit tests can better focus on individual components, testing them directly and thoroughly. This interchangeability, isolation, and testability give developers the confidence to make changes to individual components knowing that their changes have not inadvertently or adversely affected other areas of the application. For many developers, this ability to confidently change any part of their source code translates to application maintainability.
The MVVM Pattern
MVVM is one in a family of several architectural patterns that primarily focus on a separation of concerns in which layers must claim responsibility for their own logic and nothing more. The MVVM pattern achieves this separation of concerns by defining three application layers:
- Business Model (or simply "Model"): the layer defining the core business logic—representing the real "business value" or the true reason users are interested in using the application
- View: the interface through which the application accepts input from and provides feedback to the user
- ViewModel: the intermediary between the Model and the View, translating the Business Model into a format that the View can easily consume and responding to user interaction with the View. Although the Business Model may be the reason users want to use an application, the ViewModel provides a usable interface to the Business Model to the View.
The MVVM pattern and XAML-based platforms are an excellent pairing because of the powerful data-binding capabilities XAML provides. By taking advantage of these data-binding capabilities, developers can create impressive MVVM applications using ViewModels implemented with nothing more than core .NET Framework functionality, such as the INotifyPropertyChanged interface. However, several MVVM frameworks offer better ways to take advantage of some more advanced features than those offered out of the box from the .NET Framework.
One such framework is the MVVM Light Toolkit, a popular open source framework created and maintained by Laurent Bugnion. The Toolkit offers a lightweight set of extensions to the WPF, Silverlight, and Windows Phone 7 platforms that can help you create simple and elegant MVVM applications. Many of the more advanced samples in this article take advantage of the capabilities provided by this framework.
The Sample Application
Speaking of the samples in this article, let's take a moment to examine the sample Windows Phone 7 stock market application, Stock Watcher, which I will refer to in this article. Stock Watcher allows users to track the status of custom stock portfolios while keeping tabs on the "hot" profit and loss leaders in the market. The application consists of three main views:
- Portfolio: a list of stocks that the user wants to track over time. This view also allows the user to add a new stock to the list.
- Market Leaders: two sets of stock quotes generated from real-time stock data, one of profit leaders (stocks that have gained the most) and another of loss leaders (stocks that have lost the most)
- Company Details: the details of a stock selected in any other area of the application, such as the Portfolio or Market Leaders views
Creating the ViewModel
There are several opinions about the most effective pairing of Views and ViewModels. Though some very simple views may not warrant their own ViewModel and some may warrant more than one ViewModel, it is usually advisable to have a one-to-one relationship. In other words, every view in your Silverlight application (be it a Page, Window, or a User Control) will generally have its own ViewModel. As such, the ViewModels shown in Figure 1 might be an appropriate solution to support the Stock Watcher application.
Figure 1: ViewModel class diagram for Stock Watcher application
The ViewModel diagram in Figure 1 enumerates several interesting details:
- StockQuote is a business model type. Take a look at the StockQuoteViewModel snippet in Figure 2, which shows that the rest of its properties are wrappers around the StockQuote instance, exposing its various properties in ways that the UI can easily bind to.
- The CompanyDetailsViewModel acts as a container for the StockQuoteViewModel, listening and reacting to changes in the rest of the application and updating the StockQuoteViewModel instance accordingly.
- Like the CompanyDetailsViewModel, the MarketLeadersViewModel, and the PortfolioViewModel classes expose the StockQuoteViewModel, only these two view models expose them as observable collections, so that the UI can react to changes to the collections (e.g., when stocks are added, removed, or updated).
- The PortfolioViewModel and MarketLeadersViewModel each expose a SelectedStockQuote property that triggers an PropertyChanged event.
- The PortfolioViewModel exposes an MVVM Light RelayCommand property for communicating with the view (more about these last two later).
ViewModels Expose View-Friendly Data
Notice how the properties of these ViewModels expose the Business Model in a way that the View can easily and directly consume. This is most evident in the ChangeAndPercentChange property of the StockQuoteViewModel, which combines two other properties of the StockQuoteViewModel, formatting the numeric types of the underlying StockQuote model into a single string. Silverlight controls such as TextArea can easily and directly bind to strings formatted in this way.
In contrast, consider what would be required if the View attempted to bind to the StockQuote object. Since the StockQuote class was created with back-end concerns and not UI in mind, the view would require some kind of type conversion and/or string-manipulation code. This code would most likely end up in the code-behind, which is one of the application's least testable areas. Of course, this logic needs to occur somewhere—we are just moving it to a layer that is more accessible to automated unit tests!
The second notable property is the IsPositive property on the StockQuoteViewModel. This property is an example of information that is not included on the underlying model, but logic that is applied to derive a flag from the Business Model that the view can leverage in deciding how to render a given Stock Quote.
The ViewModel introduces an additional layer to augment the core business model with UI-specific data and behaviors while allowing the business model to stay focused on core Business data and logic. The ViewModel also encourages Views to remain as simple as possible, abstracting much of the UI's logic and complexity.
ViewModels Interact with Services
In addition to wrapping the model to make binding to views easier, ViewModels also act as application controllers, responding to both client- and server-side changes and events. For example, the Portfolio view of the Stock Watcher application provides users with a text box in which they can type a stock ticker symbol in order to add it to the list of stocks they are watching.
Reacting to an event triggered by the user entering a stock ticker symbol in the UI, the PortfolioViewModel may make a call to a remote web service storing the user's portfolio, notifying it of the addition. Later, when the web service call returns an updated list of stock quotes, the application notifies both the PortfolioViewModel and the MarketLeadersViewModel, and they in turn will update their respective data as needed (which will, in turn, cause the views bound to the data these view models expose to change as well). This scenario clearly shows the important role that ViewModels play in an MVVM application.
Listening for Changes
ViewModels and their associated views often need to interact with each other in some way. For example, the Company Details view provides a detailed summary of a company when the user selects a stock elsewhere in the application. Likewise, stocks listed in the Market Leaders view provide the user with the ability to quickly add those stocks to their Portfolio.
If we were to use a tightly coupled approach, these scenarios might be implemented with strong references from one view to another. For example, both the Portfolio view and the Market Leaders view might require a reference to the Company Details view, setting a property directly on the Details view in response to a user clicking on one of the stock quotes that one of the Portfolio and Market Leaders views expose. While this approach may be simple and straightforward with only these few components involved, as more and more features are requested and more components are added to support these features, this approach becomes very difficult to maintain. Decoupling these components by having them trigger and respond to more generic interactions provides a much more maintainable approach.
ViewModels play an important role as the mediator between the view and the model, responding to changes in each. As such, it is important that the ViewModel be able to both listen for and react to changes in the model and the view. Technically speaking, a "model" can be anything—even a simple class—so ViewModels need a way to interact with their associated views and possibly with each other. The following are several different approaches to decoupled communication between components.
The INotifyPropertyChanged interface was introduced in .NET 3.0 as a standard approach for any given class to notify external listeners of changes to its state. By implementing this interface, any class can chose to expose changes to any of its members to any other class that subscribes to its PropertyChanged event. The INotifyPropertyChanged interface is also the standard way that Windows Phone 7 views interact with the data objects that they are bound to. Figure 3 shows an example of a class implemented with the INotifyPropertyChanged interface.
Though the INotifyPropertyChanged interface is an excellent option for an object to notify one or more listeners of changes to its state, its main detriment is that listeners need to be aware of the objects and events they are subscribing to in order to establish the relationship. Messages offer a slightly more decoupled way to create the source/listener relationship by turning it into a publisher/subscriber relationship in which the common link is a "neutral" third-party and the medium can be almost any type that the two components are both aware of.
The MVVM Light framework offers an intuitive messaging implementation. The Messenger class offers two simple methods of communication: the ability to send messages, and the ability to register to receive messages. In this way, the MVVM Light Messenger class acts as a very lightweight—but highly effective—message bus. The following is an example of the Messenger in action. It consists of two parts: the logic that sends a message and the logic to receive a message:
Sending a Message
Receiving a Message
var updatedStockQuote = args.StockQuote;
var stock = Stocks.SingleOrDefault(
x => x.Quote.Symbol == updatedStockQuote.Symbol);
if (stock != null)
stock.Quote = updatedStockQuote;
As these snippets demonstrate, sending and receiving messages is not only very loosely coupled, it's also quite easy!
Our sample Stock Watcher application leverages the messenger pattern to send and receive several messages:
- StockQuoteDataChanged messages are broadcast when the application receives updated information for a stock. This streamlines the application and enhances the user's experience by ensuring that all data is in sync, while limiting network traffic by reusing data from one service call to update data in multiple locations, possibly well beyond the scope of the initial requestor.
- StockQuoteSelectionChanged messages occur when a user selects a stock quote in the Portfolio and Market Leaders views. Notice how the ViewModels that run each of these views contain a SelectedStockQuote property. The setter on these properties resembles the code sample shown in Figure 4.
- MarketLeadersChanged and PortfolioChanged messages are broadcast when the current market leaders change (e.g., a market loss leader's price rises, taking it off the list and adding another in its place) or when the list of stocks that the user is tracking changes (e.g., when a user starts or stops watching a stock), respectively.
Figure 4: Property setter with message broadcast
The important aspect to note in regard to these messages is that the message's sender knows neither what components will receive the message it is sending nor how the receiver will handle the message. This ignorance is one more way that application components can remain isolated from one another, yet still communicate effectively.
Commands and Events
While the INotifyPropertyChanged interface and Messaging approaches provide an effective way for components to notify each other of changes to their properties, ViewModels still need to be able to react to UI events such as a mouse click, text input, or even things such as animations stopping and starting or a Timer tick. Silverlight typically exposes UI interactions via Commands—classes that implement the ICommand interface and define the logic that executes when the command is triggered as well as logic to determine whether the application is in a state in which the command applies. For example, in a text editor application, the Save behavior may only be available when the contents of a file have changed and should otherwise not be allowed to execute.
Although this approach is fairly loosely coupled, requiring a new class for every event you want to react to can get tedious. MVVM Light offers a lighter-weight alternative to the ICommand in the form of the RelayCommand (and its strongly typed counterpart, RelayCommand<T>), which allows components to declare command handlers inline.
To help illustrate this point, consider how the sample application gives users the ability to add a stock symbol to their portfolio. As might be expected, the UI portion of the implementation is a normal TextBox for the user to enter the stock symbol text, accompanied by a button to trigger the stock symbol's addition. The traditional, event handler–based approach might look something like the code shown in Figure 5.
This approach is sub-optimal for several reasons. First, it fails to leverage XAML's powerful data-binding capabilities. Second, it introduces code into the code-behind! While the logic introduced into the code-behind is somewhat limited by calling into the ViewModel as soon as possible, consider the RelayCommand approach that eliminates this logic altogether, shown in Figure 6.
MVVM Light's Command and Command Parameter button extensions now replace the Click event handler and code-behind, binding this behavior instead to a RelayCommand defined in the ViewModel. This approach allows developers to maintain logic in a single place (the view model) by avoiding the need for code-behind files. In this way, the RelayCommand is one more tool to assist in creating highly maintainable applications.
Testing Windows Phone 7 ViewModels
One of the biggest benefits of the ViewModel approach is that it provides a UI-agnostic layer that is very easy to instantiate and test. A loosely coupled application is a boon to unit testing because components can easily run in isolation. What's more, since the dependencies between components are either weak or nonexistent, they can be easily substituted for other implementations, allowing testers to further control the testing environment.
Though unit testing Windows Phone 7 Silverlight libraries requires some special configuration, applying automated unit testing techniques to this platform is still quite possible.
Configuration and Setup
The typical approach to unit testing .NET assemblies is to create a new unit test project using Visual Studio's Test Project project template. Among other things, this project template includes references to the Microsoft.VisualStudio.QualityTools.UnitTestFramework assembly containing Visual Studio's unit testing framework. If you attempt to add a reference to your Windows Phone 7 Silverlight application, however, a variety of error messages will keep the unit test project from successfully compiling or executing because the .NET Framework and Windows Phone 7 projects simply don't mix.
Luckily, some folks at Microsoft have noticed this issue and offered a workaround. Though it may not be considered a "released product" and is somewhat difficult to locate, Jeff Wilcox provides a version of the Silverlight Unit Test Framework compiled against the Windows Phone 7 Silverlight assemblies. Adding a reference to this special Silverlight Unit Test Framework assembly version exposes classes and attributes with the same names as those found in the standard Visual Studio Unit Testing assembly!
Writing and Executing Unit Tests
Since the class and attribute names are the same, developers accustomed to working with the Visual Studio Unit Testing library should feel right at home writing tests against the Silverlight Unit Test Framework. For instance, a typical unit test written with either framework may look something like the code in Figure 7.
Now for the tricky part. After following the previous instructions, the new unit test project will successfully compile, ready to be executed by the test fixture runtime. Though some frameworks (such as the wonderful TestDriven.Net plug-in) will gladly execute the tests without issue, Visual Studio's built-in test execution features refuse to recognize that the Windows Phone Class Library project type can contain unit tests.
Luckily, the special Silverlight Unit Test Framework package contains a special test fixture runtime that executes within a Windows Phone 7 application. To use this special test fixture, create a new Windows Phone 7 application to host this runtime and act as a host to the unit tests. Then, attach the event handler as shown in Figure 8 to the Loaded event in the code-behind of the MainPage.xaml. Once this handler is in place, executing the Windows Phone application should present you with the Unit Test System's home page, shown in Figure 9.
Figure 9: Unit Test System home page
After confirming that the Silverlight Unit Test fixture runner is properly configured, feel free to start adding unit tests to this project. The following screenshots in Figures 10A through 10D show an example test run. These screenshots show the various levels of the test runner results. Figure 10A presents a list of all the test classes in the project, providing a high-level overview of the passing and failing tests.
Figure 10A: Test results, screen 1
Figure 10B shows a drill-down into the offending test class, listing the exact tests that failed.
Figure 10B: Test results, screen 2
Figures 10C and 10D show examples of unit test details, the first for a passing test, and the second for a failing test.
Figure 10C: Test results, screen 3
Figure 10D: Test results, screen 4
As you can see, despite the lack of built-in support from Visual Studio, unit testing Windows Phone 7 applications is very doable.
A Foundation to Build On
With any luck, this article has provided you with enough information and understanding to effectively leverage the Model-View-ViewModel pattern in your Windows Phone 7 applications, as well as apply appropriate levels of unit test coverage. Although the experience may not be quite the same as working with other .NET platforms, the Windows Phone 7 platform still enables developers to create robust, testable, and maintainable applications. What's more, the Windows Phone 7 platform and its associated tooling are still relatively young and are bound to mature into more robust forms that better resemble the experiences we appreciate in other platforms today.
Jess Chadwick is a Microsoft MVP; an independent consultant at HomeNet; a speaker and member of the philly.net user group; and a leader, webmaster, speaker, and member at NJDOTNET - Central NJ .NET User Group.