Windows Phone 7 – MVVM Light and Unit Testing Example

Posted by: | Technical |

Introduction

This post assumes you are doing or have done some Windows Presentation Foundation (WPF), Silverlight (SL) or Windows Phone 7 (WP7) development in the past and are eager to get some unit testing going in your WP7 applications.

It should get you started with setting up a solution structure which supports WP7 unit testing and full source code (including all referenced 3rd party libraries) is supplied at the end of the article. The core purpose is to demonstrate core testability via separation of the view model from the view.

System Requirements

I’ve checked everything against the latest public beta release of the developer tools (as of 15/07/2010) from http://developer.windowsphone.com. Please make sure you have this installed. I’m using Visual Studio 2010, but it all should work ok with Visual Studio Express 2010 that comes with the developer tools installation.

Choosing an MVVM Framework

MVVM (Model-View-ViewModel) is an architectural pattern well described by Josh Smith in his MVVM MSDN Article. When you use MVVM in your WP7 application, it becomes more suited to automated unit testing. Testability of WP7 applications relies on a clean separation between the various layers of our WP7 application, particularly between the View (the .xaml UI construct) and the ViewModel (the .cs class that is usually set as the DataContext of the View).

There are some great MVVM frameworks out there for Silverlight including Prism combined with the Managed Extensibility Framework (now part of .net 4 and Silverlight 4). However, WP7 is relatively new and these more ‘full on’ practices and frameworks are not yet usable within WP7 which is largely based on SL3 (with a bit of SL4 sprinkled in).

For WP7 I’ve opted for MVVM light as it appears to me to deliver the best ‘bang for buck’. It’s easy to set up and gives you the core separation of concerns between view and model in a nice simple way. It provides…

  • A base class for your View Model classes called ‘ViewModelBase’
  • A commanding framework to bind UI events to the ViewModel directly in xaml (no code behind event handlers)
  • A messaging framework to decouple View Models
  • Various snippets, project and item templates for Visual Studio

This post makes use of the ViewModelBase class and the commanding framework to abstract out event handling. There is a commanding framework in SL4, but this is not available within WP7 (being based largely on SL3). MVVM Light therefore comes in particularly handy here.

I’m not using the messaging framework in this example or delving into other related topics like service location/dependency injection of view models to keep things simple. You can naturally extend things to support these features once you have got the core separation in place.

Choosing a Unit Testing Framework

A quick search brought me to Jeff Wilcox’s blog on this and his out of band release of the Silverlight Unit Testing Framework for Windows Phone 7 (WP7) which can be found here http://www.jeff.wilcox.name/2010/05/sl3-utf-bits/. I believe this is your only option at this stage, and I would imagine this will be formalised in some way as the official WP7 unit testing framework in due course.

Solution Structure

Windows Phone 7 Testing - Solution Structure

Windows Phone 7 Testing - Solution Structure

We have 2 projects in our WP7UnitTestSample solution, Sample.Phone and Sample.Phone.Tests. The Sample.Phone is the main WP7 application that you would be deploying to end users. The WP7.Phone.Tests is another WP7 application which you will run simply to test out your application.

The WP7 Core Application Project

This project is pretty simple, we have a MainPage.xaml which shows a text box, a button and text block to display results of clicking that button and submitting the text. The core xaml of the page is shown below.

 <Grid x:Name="LayoutRoot">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" >
            <TextBlock Text="Test Text (6-15 chars valid)" />
            <TextBox Width="300" MaxLength="20" x:Name="TestText" Height="49" Text="{Binding TestText, Mode=TwoWay}" FontSize="12" />
            <Button x:Name="TestTextSubmit" Content="Send Test Text" Width="300">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <cmd:EventToCommand Command="{Binding TestTextButtonClick}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <!-- result here-->
            <TextBlock x:Name="Result" Text="{Binding StatusCode, Mode=TwoWay}" Height="80" Width="300" />
        </StackPanel>
    </Grid>

The View Model is defined as an application resource within App.Xaml, and referenced as a StaticResource in the MainPage.xaml as the DataContext of MainPage.xaml. (You can use the ViewModelLocator approach within the MVVM Light framework to avoid hard wiring, but not really necessary for apps where you don’t need this flexibility).

DataContext="{StaticResource MainPageViewModel}"

And here’s how you add a View Model as an application resource:

<Application.Resources>
<viewModels:MainPageViewModel x:Key="MainPageViewModel" />
</Application.Resources>

Note that there is nothing added to the code behind MainPage.xaml.cs. Having empty code behinds isn’t really a goal in itself (although it can be a rather satisfying pursuit if you’re so inclined), however you should ensure that any non View specific code is placed away from your View’s code behind as much as possible so it can be easily tested.

In this example we have two way data binding from the text box which contains the text to be submitted and also the text block  which will show the results of the submission. So far so normal. The MVVM Light framework (specifically EventToCommand) is then used to link the button click to the ViewModel by way of a bound command rather than a strongly coupled link to an event handler within the code behind of the MainPage.xaml.

Let’s take a look at the MainPageViewModel.cs class which can be found in the ViewModels folder of the core Sample.Phone project.

    public class MainPageViewModel : ViewModelBase
    {
        private string _statusCode = String.Empty;
        private string _testText = String.Empty;

        public MainPageViewModel()
        { }

        public string StatusCode
        {
            get
            {
                return _statusCode;
            }
            set
            {
                _statusCode = value;
                RaisePropertyChanged("StatusCode");
            }
        }

        public string TestText
        {
            get
            {
                return _testText;
            }
            set
            {
                _testText = value;
                RaisePropertyChanged("TestText");
            }
        }

        public ICommand TestTextButtonClick
        {
            get
            {
                return new RelayCommand(() => ProcessTestText(), () => ProcessTestText_CanExecute());
            }
        }

        public void ProcessTestText()
        {
            this.StatusCode = "SUCCESS";
        }

        public bool ProcessTestText_CanExecute()
        {
            if (String.IsNullOrEmpty(this.TestText) || this.TestText.Length < 6 || this.TestText.Length > 15)
            {
                this.StatusCode = "FAILURE - Invalid test text!";
                return false;
            }
            return true;
        }

    }

Firstly, notice how we have the 2 dependency properties TestText and StatusCode to support the databinding to the xaml UI elements. Secondly we have an ICommand bound to the TestTextButtonClick EventToCommand which returns a RelayCommand.

This is an interesting one because when this is fired, it will do 2 things. It will first of all call ProcessTestText_CanExecute() which is essentially how you validate whether or not the event can proceed. Notice how we abstract out the business logic of validating the UI here away from the View. We’re just setting the StatusCode text so that the failure of the user to enter a valid TestText value is then reflected back to the user.

Assuming this method returns true then ProcessTestText() is called which allows to process the data submitted by the user. In this case we just write out a success value which will then be reflected back in the view to let the user know everything is ok.

The idea here is that your ViewModel could be going to a web service, database etc. and your View wouldn’t care. We have completely separated the ViewModel from the View and only have a single line of code linking the two (the initial setting of the DataContext).

All well and good. Now, onto our view model tests.

The WP7 Test Application Project

Open up the Sample.Phone.Tests project and upon opening MainPage.xaml.cs you will see the following code in the constructor. This is all it takes to set up the WP7 app to run the tests found within the project.

            // set up unit testing
            Content = UnitTestSystem.CreateTestPage();
            IMobileTestPage imtp = Content as IMobileTestPage;

            if (imtp != null)
            {
                BackKeyPress += (x, xe) => xe.Cancel = imtp.NavigateBack();
            }

We have a single test class in the ViewModels folder which is MainPageViewModelTests.cs. If you take a look at this you will see that there are various test methods testing one of our View Model classes within the main Sample.Phone application.

  [TestMethod]
        public void Constructor_InstantiatesSuccessfully()
        {
            var sut = new MainPageViewModel();
            Assert.IsNotNull(sut);
        }

        [TestMethod]
        public void TestTextButtonClick_CanExecute_ShortTestText_Failure()
        {
            var sut = new MainPageViewModel();
            sut.TestText = "short";
            Assert.IsFalse(sut.TestTextButtonClick.CanExecute(null));
        }

        [TestMethod]
        public void TestTextButtonClick_CanExecute_LongTestText_Failure()
        {
            var sut = new MainPageViewModel();
            sut.TestText = "farfarfarfartoolong";
            Assert.IsFalse(sut.TestTextButtonClick.CanExecute(null));
        }

        [TestMethod]
        public void TestTextButtonClick_CanExecute_Success()
        {
            var sut = new MainPageViewModel();
            sut.TestText = "just right";
            Assert.IsTrue(sut.TestTextButtonClick.CanExecute(null));
        }

        [TestMethod]
        [Asynchronous]
        public void TestTextButtonClick_TestText_PropertyChange_Success()
        {
            bool success = false;
            var sut = new MainPageViewModel();
            sut.PropertyChanged += (sender, e) =>
                {
                    if (e.PropertyName == "TestText")
                    {
                        success = sut.TestText == "changing";
                    }
                };

            sut.TestText = "changing";
            Assert.IsTrue(success);
           EnqueueTestComplete();
        }

The Silverlight Unit Testing Framework is based on the standard Visual Studio Unit Testing so if you have used this you will be familiar with the annotations. As you can see we are able to test instantiation of the MainPageViewModel along with various failure and success paths.

One thing I really want to highlight is the availability of the [Asynchronous] attribute which is important because a lot of the time your ViewModel may be calling out (either directly or via some other layer) to a web service and all service calls must be asynchronous in WP7 (being based mostly as it is on SL3).

In this example we are keeping things simple and testing that the TestText property has changed correctly by hooking off the PropertyChanged event of that Dependency Property. Notice that you call EnqueueTestComplete() when your happy for the test to end.

To run the tests, ensure that Sample.Phone.Tests is set as the startup project in Visual Studio and hit CTRL+F5. You should then see that all tests are passing with the following screen:

Windows Phone 7 All Tests Passing

Windows Phone 7 All Tests Passing

Conclusion

With a little bit of effort you can ensure that you have basic clean separation between your View and View Model layers in WP7. From this, you can easily test your View Model operations from a test project that will give you more complete confidence in the correct behaviour of your application.

More Reading

I highly recommend getting Josh Smith’s book on MVVM.

Shawn Wildermuth’s article on MVVM on MSDN is also worth a read

Download

Windows Phone 7 – MVVM Light and Unit Testing Sample

3 Responses to Windows Phone 7 – MVVM Light and Unit Testing Example

  1. SmartyP says:

    I’ve noticed that if the system tray is showing at the top, then the results (number of pass/fail) gets cut off at the bottom – you can see it in the screenshot you posted.

    All I have found to get rid of this is to set SystemTray.IsVisible to false, but you cannot do this in the constructor without receiving the error “To set SystemTray visibility the RootVisual must be a PhoneApplicationFrame and its Content must be a PhoneApplicationPage”.

    The only solution I have found so far is to use this code in the MainPage.xaml.cs instead:
    public MainPage()
    {
    InitializeComponent();

    this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
    SystemTray.IsVisible = false;
    Application.Current.RootVisual = UnitTestSystem.CreateTestPage();
    }

  2. Dina says:

    I didn’t know DataContext could be added to mark up so I downloaded to see where the DataContext we. It may be work a XAML markup code snippet to show others this ability.