Dotneteers.net
All for .net, .net for all!

Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit

VBandi's blog

Syndication

Subscribe

Generic Content

In the previous posts of this series, we managed to get NUnit up and running to test WP7 code outside of the Windows Phone Emulator, in test runners such as NUnit, ReSharper and NCrunch, but paid the price by running into assembly load issues. We created a TestBase class to be the base class for our classes, and added convenience functions to it such as setting a global General.IsTesting flag, comparing arrays and verifying whether INotifyPropertyCollection calls have been performed properly.

In this post, I am going to concentrate on testing ViewModels that use Laurent Bugnion’s MVVM Light Toolkit.

Adding MVVM Light to the Project

Let’s start by adding MVVM Light from Nuget (I am using only the libraries for now):

image

Now we can change our Calculator class to inherit from ViewModelBase. Which also means that we can get rid of our existing PropertyChanged event and its RaisePropertyChanged invoker method as well, since they are implemented in one of our base classes.

Note: to compile the project, you’ll also have to add the MVVM Light dlls to the Test project.

All our tests still pass, proving that MVVM Light’s RaisePropertyChanged method works just like ours did. Phew.

Verifying Design Mode

The ViewModelBase class in MVVM Light has a very useful IsInDesignMode property that allows us to determine if the code is running in a design tool, and do things like creating fake test data for the designer to use instead of empty TextBoxes and Lists. This property can also be used to make sure that you are not trying to access a database from within Blend by making sure you only connect to the database or cloud service when the app is running “for real”.

Unfortunately, as soon as you access the IsInDesignMode property, the unit tests crash:

image

This looks awfully like the crash we experienced in the previous part with ObservableCollections. The actual reason is that the setter of this property accesses the DesignerProperties.IsInDesignTool property, which causes an assembly load failure. The solution is pretty similar: we have to make sure the IsInDesignMode never gets called. We can do this by first checking for our General.IsTesting property:

public Calculator()
{
    if (!General.IsTesting && IsInDesignMode)
    {
        //do design time setup

    }
    else
    {
        //do normal initialization
    }
}

And the tests pass again. Alternatively, if Laurent provides us with a way to set the IsInDesignMode property from our tests, we could simply set that and the code would never have to access DesignerProperties.IsInDesignTool. 

Verifying if Message is sent

Messaging has to be one the my favorite features of MVVM Light Toolkit. It allows loose coupling of ViewModels, sometimes even Views without having to worry about memory leaks.

When testing, you probably want to make sure that your ViewModel has sent (or hasn’t sent) a Message. Luckily, Laurent made the Messaging infrastructure extensible for exactly this reason. We can create a MessengerSpy class, which logs every message that has ever been sent through the Messenger.

public class MessengerSpy : Messenger
{
    public List<object> SentMessages = new List<object>();

    public bool HasSentMessage<T>()
    {
        return SentMessages.Any(o => o is T);
    }


    public override void Send<TMessage>(TMessage message)
    {
        SentMessages.Add(message);
    } 
}

Note that the message doesn’t actually get sent, only stored. The reason is that we would run into another one of those pesky assembly load failures.

In the TestBaseSetup method, we use this spy class and set it up so that a new spy is created for every test:

//set up message logging
messengerSpy= new MessengerSpy();
Messenger.OverrideDefault(_msngr);

So, how do we use this? Suppose we want to send a message whenever X changes in the Calculator ViewModel. We have an XChangedMessage for this purpose:

public class XChangedMessage
{
    public int NewX { get; set; }
}

Since TestBase.messengerSpy is declared protected, it can be accessed from our tests. To make sure the message has been sent, we can simply use the HasSentMessage method:

[Test]
public void XChangedMessageShouldBeSentAfterXChanges()
{
    _calc.X = 10;
    Assert.IsTrue(base.messengerSpy.HasSentMessage<XChangedMessage>());
}

This fails until we append the following line to the setter of the Calculator.X property:

Messenger.Default.Send(new XChangedMessage());

If we want to go one step further and verify that the NewX value is set properly, then we can do the following:

[Test]
public void XChangedNewXShouldBeSentAfterXChanges()
{
    _calc.X = 10;
    Assert.IsTrue(messengerSpy.SentMessages.Any(m => ((XChangedMessage)m).NewX == 10));
}

And of course, to make this one pass, we have to set the value of NewX in the X setter when the message is created:

Messenger.Default.Send(new XChangedMessage {NewX = 10});

Testing RelayCommands

Fortunately, testing RelayCommands is straightforward. Let’s create a ResetXToZero command (which should not be executable when X is already 0) like this:

 ResetXToZero = new RelayCommand(() => X = 0, () => X != 0);

We can easily test it using the funky Sequential test attribute for zero, positive and negative X values:

[Test, Sequential]
public void VerifyExecuteResetXCanExecute(
    [Values(0, 1, -1)] int x,
    [Values(false, true, true)] bool expected
    )
{
    _calc.X = x;
    Assert.AreEqual(expected, _calc.ResetXToZero.CanExecute(null));
}

Summary

This concludes my short blog series on using NUnit to test Windows Phone applications. As you can see, the method outlined here has quite a few issues, especially when you want to load assemblies beyond the basics. However, this technique was extremely useful for me during our last project, where complex calculations had to be tested that did not rely on any platform-specific functionality – but still took advantage of the Math functions and a huge amount of Linq expressions, IQueriables, etc.

Source Code

You can download the source code for this little project here.


Posted Aug 17 2012, 02:40 AM by vbandi
Filed under:

Comments

Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit wrote Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit
on Fri, Aug 17 2012 12:31

Pingback from  Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit

Dew Drop – August 17, 2012 (#1,384) | Alvin Ashcraft's Morning Dew wrote Dew Drop &ndash; August 17, 2012 (#1,384) | Alvin Ashcraft&#039;s Morning Dew
on Fri, Aug 17 2012 14:48

Pingback from  Dew Drop – August 17, 2012 (#1,384) | Alvin Ashcraft's Morning Dew

Using NUnit to test Windows Phone 7 applications: ViewModels and MVVM Light Toolkit | azkafaiz.com wrote Using NUnit to test Windows Phone 7 applications: ViewModels and MVVM Light Toolkit | azkafaiz.com
on Sat, Aug 18 2012 9:05

Pingback from  Using NUnit to test Windows Phone 7 applications: ViewModels and MVVM Light Toolkit | azkafaiz.com

Dennis Doomen wrote re: Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit
on Wed, Aug 29 2012 6:18

Since you're promoting unit testing anyway, why don't you include a decent assertion framework to make those tests even more intention revealing?

fluentassertions.codeplex.com/documentation

vbandi wrote re: Using NUnit to test Windows Phone 7 applications Part 3: ViewModels and MVVM Light Toolkit
on Wed, Aug 29 2012 11:29

Dennis: This is just showing that NUnit is possible for Windows Phone. I didn't want to deviate from the core message by adding additional frameworks, etc.

Having said that, thanks for bringing this up in the comments.