Geeks With Blogs
Etienne Giust's .NET notes Some .NET tips and tricks for me to remember. That might help you too

If you're like me and are using MVVMLight to build Windows Phone apps, you probably want to unit test your ViewModels as well.

One of the benefits of the MVVM pattern is the separation of concerns between the View (page holding the xaml layout and bindings) and the ViewModel which holds the data to be bound.

This allows the ViewModel to be easily testable, or so they say. In the end, it is quite difficult to find some useable tutorial doing exactly that. To the point you might ask yourself : " do the people who use MVVMLight really do unit testing of their ViewModels ?"

 

After a great deal of research, I came up with a Tutorial of my own, thanks to

http://rabeb.wordpress.com/2011/08/14/mango-baby-steps-unit-testing-your-app/

and http://juarola.wordpress.com/2011/09/06/unit-testing-windows-phone-7-mvvmlight-viewmodels-with-7-1-sdk-rc-nunit-and-moq/

and http://www.jeff.wilcox.name/2011/06/updated-ut-mango-bits/

 

So let's do this.

We are going to build a testable WP7 MVVMLight project (named TestableWP7MVVMLight ), which is really a standard MVVMLight Project holding the ViewModels we want to test.

We are also going to build a unitTest project  (named WP7MVVMLight.UnitTest) which will perform the unit testing of our first project.

 

Before starting, ensure having the following components installed on your system :

  • Visual Studio 2010
  • The Windows Phone 7.1 SDK (Mango)
  • MVVM Light Toolkit installed on your Machine (use the MSi to install the project templates in VS2010 , the Nuget package does not do that, at least with the version I used). I used the v4 beta 1

 

 

Step 1: Creation of the MVVMLight application to be tested

 Create a New MVVMLight (WP71) Project : TestableWP7MVVMLight

 Build the project and check that the application is functional. It should display "Welcome to MVVM Light" on the display.

Step 2 : Creation of the test project

 

Now, you might ask yourself : why not create a classic C# test project and reference our TestableWP7MVVMLight and then test it ?

Well, Silverlight and desktop applications use different CLR. It is not possible to reference a Silverlight (or WP7) assembly in a classic test project.

So what we do is create a New MVVMLight (WP71) Project: WP7MVVMLight.UnitTest

 We will later rig up the test project with all the necessary testing assemblies

 

It should build flawlessly, as for the moment it is just another basic MVVMLight project.

Now we need to add the following Silverlight Unit Test Framework dlls to our project :

  • Microsoft.Silverlight.Testing.dll
  • Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll

 

You will find those dlls here : http://www.jeff.wilcox.name/2011/06/updated-ut-mango-bits/

Check periodically Jeff Wilcox’s blog for up to date versions.

 

Now reference the two dlls in your WP7MVVMLight.UnitTest project

You will have VS2010 complain that "Adding reference to a Windows Phone XNA assembly is safe. However adding reference to a Silverlight assembly may lead to unexpected application behavior …" Ignore this and press Yes;

Your references should look like this :

 image

 Check that compilation goes well.

 

Step 3 : Run the empty test project

 

Now we need to edit the MainPage.xaml.cs file in order to have the WP7MVVMLight.UnitTest (which is still and will remain a windows phone app) actually running the tests and display results :

 

using Microsoft.Phone.Controls;
using Microsoft.Silverlight.Testing;  // <--- Important

namespace WP7MVVMLight.UnitTest
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            const bool runUnitTests = true;
            if (runUnitTests)
            {
                Content = UnitTestSystem.CreateTestPage();
                IMobileTestPage imtp = Content as IMobileTestPage;
                if (imtp != null)
                {
                    BackKeyPress += (x, xe) => xe.Cancel = imtp.NavigateBack();
                }
            }
        }
    }
}

Note : editing the .xaml.cs file is not compliant with MVVM philosophy but in this instance, we have to do it .

Now if you run the WP7MVVMLight.UnitTest application, you'll get a dashboard of your test.  Those tests will be automatically launched.

For the moment we have not tests, though

Step 4 : A first Test

 

We need first to reference our main phone app into the test project :

 

image

 

Then let’s create a test class inside a new folder named Tests

 

image

 

DemoTest.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace WP7MVVMLight.UnitTest.Tests
{
    [TestClass]
    public class DemoTest
    {
        [TestMethod]
        public void AlwaysWorkingUnitTest()
        {
            //Assert.Inconclusive("We need to write our first unit test");
            Assert.AreEqual(1, 1);
        }
    }
}

 

And now, when you launch the WP7MVVMLight.UnitTest application, the test should execute and pass:

 

image

 

Now, let’s add this simple test method to our DemoTest.cs :

 


[TestMethod]
public void MainViewModel_ClassicInstanciation_UnitTest()
{
    // Instantiate the viewModel we want to test
    var mainViewModelToTest = new TestableWP7MVVMLight.ViewModel.MainViewModel(new TestableWP7MVVMLight.Design.DesignDataService());

    // assert a property of the viewmodel
    Assert.AreEqual(mainViewModelToTest.WelcomeTitle, "Welcome to MVVM Light [design]");
}

 

Here ! You are actually testing your viewmodel (the MainViewModel from the first TestableWP7MVVMLight project).

 

A little bit of explanation about what is going on here for people who are not familiar with the MVVMLight project template:

MainViewModel is instantiated with the design data service from DesignDataService.cs. It could really be any IDataService implementation , but  I chose to use the DesignDataService from the original project. Of course, you could redefine another implementation of IDataService  locally.

 

During instantiation of MainViewModel , the property WelcomeTitle is set based on the dataservice passed to the constructor; (this is really the pre-existing logic inside our TestableWP7MVVMLight  MainViewModel.cs file )

 

So we explicitely instanciated a ViewModel and checked some property. But instead doing that, couldn’t we just use the IOC

 

Step 5 : Same but different : using the IOC

 

Here is the exact same test, but the instantiation of the ViewModel is made through a call to GetInstance.

The ViewModel is previously registered, as well as the implementation of IDataService which is to be used throughout the test

 


[TestMethod]
public void MainViewModel_IOCInstanciation_UnitTest()
{
    // Set up the IOC
    SimpleIoc.Default.Register<TestableWP7MVVMLight.Model.IDataService, TestableWP7MVVMLight.Design.DesignDataService>();
    SimpleIoc.Default.Register<TestableWP7MVVMLight.ViewModel.MainViewModel>();

    // Instantiate the MainViewModel - MVVM Style
    var vm = ServiceLocator.Current.GetInstance<TestableWP7MVVMLight.ViewModel.MainViewModel>();

    // assert a property of the viewmodel
    Assert.AreEqual(vm.WelcomeTitle, "Welcome to MVVM Light [design]");
}

 

 

Great. You can now be happy and unitTest your ViewModels in true MVVM style.

 

 

Discussion

 

At that point, I am not aware of a way to leverage this inside an Industrialization process.

Since the actual testing and test results are done from the Windows Phone GUI, it does not seem possible to have automated tests being performed as a Build task for example.

 

If you have any suggestion on the subject, please leave me some comments.

Posted on Tuesday, February 14, 2012 11:08 PM | Back to top


Comments on this post: Unit Testing an MVVMLight Windows Phone 7.5 (Mango) application

# maybe a little bit of clue there
Requesting Gravatar...
http://justinangel.net/WindowsPhone7EmulatorAutomation

and

http://justinangel.net/WP7
Left by Bob on Feb 17, 2012 2:57 AM

Your comment:
 (will show your gravatar)


Copyright © Etienne Giust | Powered by: GeeksWithBlogs.net