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
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 :
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 :
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.Silverlight.Testing; // <--- Important
public partial class MainPage : PhoneApplicationPage
const bool runUnitTests = true;
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 :
Then let’s create a test class inside a new folder named Tests
public class DemoTest
public void AlwaysWorkingUnitTest()
//Assert.Inconclusive("We need to write our first unit test");
And now, when you launch the WP7MVVMLight.UnitTest application, the test should execute and pass:
Now, let’s add this simple test method to our DemoTest.cs :
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
public void MainViewModel_IOCInstanciation_UnitTest()
// Set up the IOC
// 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.
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.