Windows Phone 7, MVVM and TDD (Part 2 – The first test)
by Peter Daukintis
First, I will create a new project in Visual Studio using the MVVM Light project templates (MVVM Light is not a requirement really it just makes the implementation of MVVM less repetitive – any compatible MVVM framework would do, or you could just roll your own).
I got a compatibility warning dialog when I executed this step as the version of the MVVM Light has not been updated to support the Windows Phone application manifest. This is easily fixed by adding the following to the WMAppManifest.xml file in the project.
<Capabilities> <Capability Name="ID_CAP_NETWORKING" /> <Capability Name="ID_CAP_LOCATION" /> <Capability Name="ID_CAP_SENSORS" /> <Capability Name="ID_CAP_MICROPHONE" /> <Capability Name="ID_CAP_MEDIALIB" /> <Capability Name="ID_CAP_GAMERSERVICES" /> <Capability Name="ID_CAP_PHONEDIALER" /> <Capability Name="ID_CAP_PUSH_NOTIFICATION" /> <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" /> </Capabilities>
Build and run the application which will start up the emulator and you should see something similar to the following:
Now add the unit test project as follows:
- Add a new ‘Windows Phone Application’ project to your solution
- Rename to WP7Login.Tests
- Delete the MainPage.xaml file
- Set the RootVisual to a page created by the unit test framework: </li></li>
Edit the app.xaml.cs App constructor so it looks like this (i.e. add the code to set the RootVisual)
public App() { UnhandledException += new EventHandler<ApplicationUnhandledExceptionEventArgs>(Application_UnhandledException); InitializeComponent(); RootVisual = UnitTestSystem.CreateTestPage(); }
Now, set the test project as the solution startup project and run the test project. You should see something like the following:
Since we haven’t written any tests yet there is nothing to run. So let’s start by creating a very simple test. First add a new class to the Test project called MainViewModelTests (the MVVM Light template provides us with a pre-created MainViewModel class which I will use exclusively for this demonstration). Also, the tests I will write are for demonstrative purposes – in a real life project I would strive for maximum coverage. Adorn the class with the TestClass attribute and derive it from the SilverlightTest class (from the unit test tools).
using Microsoft.Silverlight.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace WP7Login.Tests { [TestClass] public class MainViewModelTests : SilverlightTest { } }
Add a test method to the class like so…
[TestMethod] public void UsernameText_SetValue_RaisesPropertyChanged() { }
(I use Resharper code templates here for fast generation of the test method signature following my preferred naming convention which is Method_Scenario_ExpectedResult).
In order for my proposed ‘UsernameText’ property to take part in data-binding (which is crucial to support MVVM) it must support the INotifyPropertyChanged interface. My first test is to check that this works correctly.
[TestMethod] public void UsernameText_SetValue_RaisesPropertyChanged() { var mainViewModel = new MainViewModel(); bool propChanged = false; mainViewModel.PropertyChanged += (s, e) => { if (e.PropertyName == "UsernameText") { propChanged = true; } }; mainViewModel.UsernameText = "fred"; Assert.IsTrue(propChanged); }
This is my first go at the test. Please note that the MainViewModel class already supports the INotifyPropertyChanged interface – this is provided by the MVVM Light toolkit (by deriving from ViewModelBase). I have written this code before actually adding the property to the view model so I will also need to add the property.
private string _usernameText; public string UsernameText { get { return _usernameText; } set { if (_usernameText != value) { _usernameText = value; RaisePropertyChanged(() => UsernameText); } } }
This is a standard implementation aside from the type-safe RaisePropertyChanged method. This achieves the same end result as the standard version (which takes a string of the property name as a parameter). The problem with this is that if you spell the property name wrong this can lead to some debugging pain. This is implemented as follows:
private void RaisePropertyChanged<T>(Expression<Func<T>> action) { RaisePropertyChanged(GetPropertyName(action)); } private static string GetPropertyName<T>(Expression<Func<T>> action) { var expression = (MemberExpression)action.Body; return expression.Member.Name; }
I added these to my view model as helpers to look up the property name automatically from the lambda expression.
Anyway, back to the UsernameText property; once this is added I can go ahead and run the first test…Here are the results…
And, clicking on the one and only test gives some further details:
So, that’s it – the environment is configured for basic MVVM and so we can run tests against the ViewModel.
Technorati Tags: MVVM,Part,Visual,Studio,requirement,implementation,framework,version,WMAppManifest,Name,ID_CAP_LOCATION,ID_CAP_SENSORS,ID_CAP_MEDIALIB,ID_CAP_GAMERSERVICES,ID_CAP_PHONEDIALER,ID_CAP_PUSH_NOTIFICATION,ID_CAP_WEBBROWSERCOMPONENT,Build,unit,Application,solution,Rename,Delete,MainPage,RootVisual,Reference,Microsoft,VisualStudio,QualityTools,Edit,code,UnhandledException,EventHandler,ApplicationUnhandledExceptionEventArgs,Application_UnhandledException,InitializeComponent,UnitTestSystem,CreateTestPage,haven,Test,MainViewModelTests,template,MainViewModel,demonstration,Also,life,coverage,Adorn,TestClass,SilverlightTest,tools,TestTools,method,TestMethod,Resharper,generation,signature,convention,Method_Scenario_ExpectedResult,UsernameText,data,interface,PropertyName,Assert,IsTrue,supports,ViewModelBase,_usernameText,result,parameter,pain,Expression,Func,action,GetPropertyName,MemberExpression,Body,Member,Anyway,Here,environment,ViewModel,templates,purposes,helpers,xamlWindows Live Tags: MVVM,Part,Visual,Studio,requirement,implementation,framework,version,WMAppManifest,Name,ID_CAP_LOCATION,ID_CAP_SENSORS,ID_CAP_MEDIALIB,ID_CAP_GAMERSERVICES,ID_CAP_PHONEDIALER,ID_CAP_PUSH_NOTIFICATION,ID_CAP_WEBBROWSERCOMPONENT,Build,unit,Application,solution,Rename,Delete,MainPage,RootVisual,Reference,Microsoft,VisualStudio,QualityTools,Edit,code,UnhandledException,EventHandler,ApplicationUnhandledExceptionEventArgs,Application_UnhandledException,InitializeComponent,UnitTestSystem,CreateTestPage,haven,Test,MainViewModelTests,template,MainViewModel,demonstration,Also,life,coverage,Adorn,TestClass,SilverlightTest,tools,TestTools,method,TestMethod,Resharper,generation,signature,convention,Method_Scenario_ExpectedResult,UsernameText,data,interface,PropertyName,Assert,IsTrue,supports,ViewModelBase,_usernameText,result,parameter,pain,Expression,Func,action,GetPropertyName,MemberExpression,Body,Member,Anyway,Here,environment,ViewModel,templates,purposes,helpers,xaml </div>
Comments