Wintellect  

Browse by Tags

All Tags » silverlight unit test   (RSS)

The Silverlight team recently posted a blog entry entitled "Vancouver Olympics - How'd we do That?" in which they detailed the massive effort across multiple partners to pull together the on-line solution for streaming HD videos, both live and on demand.

This was an exciting post for Wintellect and me because it detailed the effort we contributed to making the project a success. What's more important to me for the Silverlight community, however, is that you don't overlook the key detail they posted on the blog:

Development of a Silverlight application to interface with the service agents via WCF. This tool allows Microsoft to quickly publish new configuration files (such as web.config and clientaccesspolicy.xml) to groups of servers, as well as dynamically manipulate configuration settings through a visual interface (for example, turning off compression on a remote smooth streaming server when required) on multiple remote servers at once.

This is important because as a Silverlight developer I am constantly bombarded with questions about how viable Silverlight is, if it is ready for the enterprise and what practical application it has for business. This is a specific example where it was the right tool for the right job.

I won't go into more details about the tool other than what Microsoft has publicly shared, but I wanted to emphasize that this is another example of how Silverlight helps to solve real world problems. When looking at the requirements for the health monitoring, we had several options for a solution. In this case, WPF wouldn't have worked because they would have had to remote into the environment in order to access the tool. However, using ASP.NET and JavaScript would have required jumping through some major hoops and use of heavy controls to correctly render the user interface they required. The tool essentially parses any XML-base configuration file and allows on-line navigation and updates to that document. While this would have been possible using script, it would have taken much longer and required an extended cycle of testing to stabilize.

Due to Silverlight's unique data-binding model and full LINQ to XML support, we were able to build a solution quickly and effectively. We were also able to use the unit testing framework to build hundreds of unit tests that helped ensure a stable, thorough, and well-tested solution. Again, using scripting would have required more complicated tools that simulated user-clicks, etc. With Silverlight, we can place controls on a test surface and simulate the click events to test everything from behaviors down to internal class methods.

PRISM, or the Composite Application Library, was also crucial with the success of keeping the module light weight. There were literally dozens of functions the tool could provide but only a few might be used at any given time, so we separated the functions into independent modules that dynamically loaded as needed to provide a streamlined experience.

While I was excited to work on the project with my company, I am even more excited that it demonstrates yet again how Silverlight is the right tool, right here, right now for enterprise class applications. This is another "case study" to add to your arsenal as you answer questions about, "Is it ready?" or "Has it been done before." I believe the fact that it was so crucial both in the front end (with the live streaming experience) and back-end (with the management tools) for an incredible event like the Olympics really proves how mature and ready Silverlight is for business class applications.

Jeremy Likness

Moq is a library that assists with running unit tests by providing easily mocked objects that implement interfaces and abstract classes. You can learn more about Moq on their website. There is a distribution for Silverlight, and in this post I'll focus on some ways to use Moq for some more involved testing scenarios.

Download the source code for the example project

I started with the Simple Dialog Service in Silverlight and extended the example a bit. In the post, I promised that abstracting the dialog function behind an interface would facilitate unit testing. In this post, I'll deliver on the promise.

Adhering to the pattern I described in Simplifying Asynchronous Calls in Silverlight using Action, I created the interface for a "Thesaurus" service. In this contrived example, we are showing a list of words. You can highlight a word and see the related synonyms in another list. You may also delete the words from the list.

Because we assume in the real word that there are thousands upon thousands of available words and synonyms, the view model won't try to hold a complex object graph. I won't have a special "word" entity that has a nested list of synonyms. Instead, I'll maintain two lists: one of words, and one of the current synonyms. The service will be called when a word is selected to retrieve the list of synonyms for that word.

Enough set up ... let's take a refresher and look at the dialog service interface, along with the new thesaurus interface:

public interface IDialogService
{
   void ShowDialog(string title, string message, bool allowCancel, Action<bool> response);
}

public interface IThesaurus
{
    void GetSynonyms(string word, Action<List<string>> result);

    void ListWords(Action<List<string>> result);

    void Delete(string word);
}

As you can see, the interface is straightforward. In the sample project, I've implemented the dialog using the same code as my previous post (which involves a ChildWindow). The "implementation" of the thesaurus service actually only provides a few words and synonyms but is enough to run the application and see how it would function in the real world.

To run the actual "live" code, right-click on SimpleDialog.Web and choose "Set as startup project." Then, right-click on SimpleDialogTestPage.aspx and choose "Set as start page." Hit F5 and you'll be in business. In this screenshot, I've selected a word that we run into quite often in the development world, and you can see that it has synonyms listed for it:

The view model is straightforward. It expects an implementation of the dialog service and the thesaurus service, then manages well on its own:

public class ViewModel : INotifyPropertyChanged
{
    private readonly IThesaurus _thesaurus;

    private readonly IDialogService _dialog;

    public ViewModel()
    {
        Words = new ObservableCollection<string>();
        Synonyms = new ObservableCollection<string>();
       
        DeleteCommand = new DelegateCommand<object>( o=>ConfirmDelete(), o=>!string.IsNullOrEmpty(CurrentWord));
    }

   public ViewModel(IThesaurus thesaurus, IDialogService dialogService) : this()
    {
        _thesaurus = thesaurus;
        _dialog = dialogService;

        _thesaurus.ListWords(PutWords); 
    }

    public DelegateCommand<object> DeleteCommand { get; set; }

    public ObservableCollection<string> Words { get; set; }

    public void PutWords(List<string> words)
    {
        Words.Clear();
        foreach(string word in words)
        {
            Words.Add(word);
        }

        // default first word
        if (Words.Count > 0)
        {
            CurrentWord = Words[0]; 
        }
    }

    public ObservableCollection<string> Synonyms { get; set; }

    public void PutSynonyms(List<string> synonyms)
    {
        Synonyms.Clear();
        foreach (string synonym in synonyms)
        {
            Synonyms.Add(synonym);
        }
    }

    public void ConfirmDelete()
    {
        _dialog.ShowDialog("Confirm Delete", string.Format("Do you really want to delete {0}?", CurrentWord),
            true, b =>
                      {
                          if (b)
                          {
                              _thesaurus.Delete(CurrentWord);
                              _thesaurus.ListWords(PutWords);
                          }
                      });
    }

    private string _currentWord = string.Empty; 

    public string CurrentWord
    {
        get { return _currentWord; }
        set
        {
            _currentWord = value;
            _thesaurus.GetSynonyms(value, PutSynonyms);
            OnPropertyChanged("CurrentWord");
            DeleteCommand.RaiseCanExecuteChanged();
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Let's walk through it briefly. The constructor initializes the lists and the delete command, which requires that there is a CurrentWord selected. When the services are passed in, it requests the list of words and asks the service to call PutWords with the list. This will load the results and set a default "current word" based on the first item in the list.

The current word is interesting, because when it is set, it goes out to request a list of synonyms. This is populated to the synonym list. When the view model is constructed and the list of words is received, it will automatically fire a request for the synonyms by setting the current word. The current word also updates the DeleteCommand so it can be enabled or disabled based on whether or not a word is currently selected.

The delete command itself calls the dialog service for confirmation, and only if the user confirms will it then call the service, delete the word, and then request a new list of words.

This view model is written so that I need almost zero code behind in my user control. The XAML looks like this, and is driven completely by data-binding:

<UserControl x:Class="SimpleDialog.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  <Grid x:Name="LayoutRoot" 
        HorizontalAlignment="Center"
        VerticalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions> 
        <ListBox 
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            ItemsSource="{Binding Words}"
            SelectedItem="{Binding CurrentWord, Mode=TwoWay}"
            SelectionMode="Single"
            Grid.Row="0"
            Grid.Column="0"/>
        <ListBox
            HorizontalAlignment="Center"
            VerticalAlignment="Center"            
            Width="Auto"
            ItemsSource="{Binding Synonyms}"
            Grid.Row="0"
            Grid.Column="1"/>
        <Button 
            HorizontalAlignment="Center"
            VerticalAlignment="Center"            
            Width="Auto"
            Content="Delete"
            Grid.Row="1"
            Grid.Column="0"
            cal:Click.Command="{Binding DeleteCommand}"/>
  </Grid>
</UserControl>

The key here is the bindings from the delete button to the delete command, and the list box of words to the "current word." This allows all of the other updates to cascade accordingly. I said I had "almost no" code behind. This is because I'm traveling light and decided not to drag an IoC container into the example. Therefore, in the code behind, I manually wire up the view model like this:

public MainPage()
{
    InitializeComponent();
    DataContext = new ViewModel(new Thesaurus(), new DialogService());
}  

Now that we've set the stage, the real focus of this post is how to test what we've just created. I have a view model that does quite a bit, and want to make sure it is behaving. To make this happen, I'll do two things. First, I'll add the Silverlight Unit Testing Framework. I first discussed it in my post about unit testing views AND view models. Next, I'll navigate to the Moq page and download the Silverlight bits (all of this is included in the reference project).

My test class is "view model tests." The first thing I need to do is set up some support for the tests. We want a pretend list of words and synonyms, and mocks for the services the view model depends on. Our class starts out like this:

[TestClass]
public class ViewModelTests
{
    private readonly List<string> _words = new List<string> {"test", "mock"};

    private readonly List<string> _synonyms = new List<string> {"evaluation", "experiment"};

    private readonly List<String> _mockSynonyms = new List<string> {"counterfeit", "ersatz", "pseudo", "substitute"};

    private Mock<IDialogService> _dialogMock;

    private Mock<IThesaurus> _thesaurusMock;

    private ViewModel _target;
}

We created two words with synonym lists. The mocking of the services is as simple as declaring Mock<T>. There is more to it that we'll cover, but this gets us started. I like to always have a reference to the object I am testing as target to make it clear what the test is run for.

Now we will need to set up the view model for all of our tests. Just like with the standard unit testing framework, we can flag a method as TestInitialize to do set up before each test is run. Take a look at my setup:

[TestInitialize]
public void InitializeTests()
{
    _dialogMock = new Mock<IDialogService>();

    _thesaurusMock = new Mock<IThesaurus>();

    _thesaurusMock.Setup(
        t => t.ListWords(It.IsAny<Action<List<string>>>()))
        .Callback((Action<List<string>> action) => action(_words));

    _thesaurusMock.Setup(
        t => t.GetSynonyms(It.Is((string s) => s.Equals(_words[0])), It.IsAny<Action<List<string>>>()))
        .Callback((string word, Action<List<string>> action) => action(_synonyms));

    _thesaurusMock.Setup(
        t => t.GetSynonyms(It.Is((string s) => s.Equals(_words[1])), It.IsAny<Action<List<string>>>()))
        .Callback((string word, Action<List<string>> action) => action(_mockSynonyms));

    _target = new ViewModel(_thesaurusMock.Object, _dialogMock.Object);
}

We create a new mock for every test so the internal counters are reset. Then, it gets a little interesting. The setup command allows you to determine what an expected call will be, and to provide results. Many methods return values, and there is a Result method to use for providing what those values should be. In our case, however, the methods do not return anything because they call the Action when complete. Therefore, we set up a callback so that we can perform an action when the method is fired.

To see how that works, take a look at the first set up. We are setting up our mock for the thesaurus service. The lambda expression indicates we expect the ListWords to be called, and the parameter can be any action that acts on a list of a strings. Now the important part: the callback. The callback has the same signature as the method. When the method is called, Moq will fire the callback and send the parameters. In our case, we take the action that was passed in, and call it with our list of words. This will mock the process of the view model requesting the word list, then having the PutWords method called with the actual list.

Next, we set up the GetSynonyms method twice. This is because we want to pass a different result based on the word that the method is called with. Instead of IsAny, we'll use Is with a lambda that determines what will pass. In this way, we can compare specific values or even ranges. If the passed value is the first word, we call the action with the synonym list. If the passed value is the second word ("mock"), we call the action with the list of mocks. If any other value is passed in, we simply don't care so we haven't set that up.

The first test we'll make is for setup. In other words, after the view model is constructed, we simply want to test that everything was set up appropriately. The view model promises to provide us with lists and commands, so we need to ensure these will be available when we bind to it.

[TestMethod]
public void TestConstructor()
{
    // make sure it made the call
    _thesaurusMock.Verify(t => t.ListWords(_target.PutWords), Times.Exactly(1),
                          "List words method was not called.");
    _thesaurusMock.Verify(
        t => t.GetSynonyms(It.Is((string s) => s.Equals(_words[0])), It.IsAny<Action<List<string>>>()),
        Times.Exactly(1),
        "Synonym method never called for first word.");
    Assert.AreEqual(_target.CurrentWord, _words[0], "View model did not default target word.");
    Assert.IsNotNull(_target.DeleteCommand, "Delete command was not initialized.");
    Assert.IsTrue(_target.DeleteCommand.CanExecute(null),
                  "Delete command is disabled when selected word exists.");
    CollectionAssert.AreEquivalent(_words, _target.Words, "Words do not match.");
    CollectionAssert.AreEquivalent(_synonyms, _target.Synonyms, "Synonyms do not match.");
}

The setup commands "rigged" what we expect when a method is called. If these were the only actions we took, this would really be a "stub" (something there to make it happen) rather than a mock (something that changes and can be inspected after the test to determine the outcome). With Moq, we use verify to inspect the state of the mocked object. First, we verify that the word list was called exactly once. Next, we verify that the synonym list was called specifically with the first word. Next, we are comparing values, lists, and commands to make sure they are as we expect. For example, the view model should have already populated a list of synonyms that matches the first word, so we use the CollectionAssert to make sure the lists are equivalent.

Now we can do a little more in depth test. Let's test selection. When we select the second word by setting the CurrentWord property, the view model should call the thesaurus service to retrieve the list of synonyms for 'mock.' The test looks like this:

[TestMethod]
public void TestSelection()
{
    _target.CurrentWord = _words[1]; 

    CollectionAssert.AreEquivalent(_mockSynonyms, _target.Synonyms, "Synonyms did not update.");
}

Technically, I could have verified the call as well and if you feel that is necessary, then by all means include that test. In this case, I know the synonym list simply won't update itself, so if it ends up changing to the list I'm expected, I'm confident that the call took place. Therefore, I simply test that the mock synonyms were updated to the collection of synonyms on the view model.

What about a more complicated test? Our delete command requires confirmation, so the user doesn't accidentally delete a word they did not intend to. Therefore, we need to set up the dialog service to return the results we want. We'll have two tests: one that ensures the delete service is called when the user confirms, and another that ensures it is NOT called when the user cancels. The confirm test looks like this:

[TestMethod]
public void TestDeleteConfirm()
{
    _thesaurusMock.Setup(t => t.Delete(It.IsAny<string>())); 

    _dialogMock.Setup(
        d => d.ShowDialog(It.IsAny<string>(),
                          It.IsAny<string>(),
                          It.IsAny<bool>(),
                          It.IsAny<Action<bool>>()))
        .Callback(
        (string title, string message, bool cancel, Action<bool> action) => action(true));

    _target.DeleteCommand.Execute(null);

    _thesaurusMock.Verify(
        t => t.Delete(It.Is((string s) => s.Equals(_words[0]))),
        Times.Exactly(1),
        "The delete method was not called on the service.");
}

First we set up the service to expect the delete call. Next, we set up the dialog. We don't care about the parameters passed in. All we care about is that we call the action with "true" to simulate a user confirming the dialog. Once this is set up, we trigger the delete command, and verify that the delete service was called for the appropriate word.

For the cancel, we pass false in the action, and use Times.Never() on the method signature to ensure the delete service was not called.

Finally, because our delete command is only enabled when a current word is selected, we need to test that it is disabled with no words:

[TestMethod]
public void TestDeleteEnabled()
{
    _target.CurrentWord = string.Empty; 

    Assert.IsFalse(
        _target.DeleteCommand.CanExecute(null),
        "Delete command did not disable with empty word selection.");
}

We already tested for the positive case in the constructor. Now, we simply clear the selection and confirm that the command is no longer allowed to execute.

If you ran the application earlier, you simply need to set the "test" project as the start-up project to run the unit tests. They will run directly in the browser.

As you can see, using the MVVM pattern appropriately ensures straightforward XAML (mostly binding-driven without cluttered code-behind) and very granular testing. Tools like Moq can make it much easier to test complicated scenarios by allowing you to easily set up dependencies, mock returns, and ultimately validate that the view model is behaving the way it is expected to.

Download the source code for the example project

Jeremy Likness

One concern with the Silverlight Unit Testing Framework is that it runs on a UI thread and requires a browser to function. This makes it difficult to integrate into automated or continuous integration testing. Difficult, but not impossible.

A solution is provided by the project called StatLight which not only supports Silverlight testing automation, but actually integrates with several different unit test providers. I am focusing on the Silverlight UT for this post. The program is very flexible and will even run as an continuous test server by watching a XAP file for changes and triggering the tests when it does. It will output to the console and to an XML formatted file, making it easy to grab and process test results.

I decided to run the tests I made in the Unit Testing Asynchronous Behaviors in Silverlight post. First, I headed over to the StatLight web site and downloaded the project. I simply unzipped it into a folder to "install."

Next, I copied the XAP file for my tests, called PRISMMEF.Tests.xap, into the folder with StatLight (you can reference the full path, this was just for convenience). I created a subdirectory called reports.

I launched a command line as administrator. StatLight launches its own web service so elevated permissions are required to allow it to bind to the appropriate ports. At the command line, I ran the following. It started the test run, placed a dot on my screen for every test run, and then completed.

Silverlight Unit Test Automation

This resulted in the following output as a file called report.xml:

<StatLightTestResults xapFileName="PRISMMEF.Tests.xap" total="6" ignored="0" failed="0" dateRun="2010-01-08 19:15:18">
  <tests>
    <test name="PRISMMEF.Tests.Common.PartModuleTest.TestConstructor" passed="True" timeToComplete="00:00:00.0290016" />
    <test name="PRISMMEF.Tests.Common.PartModuleTest.TestInitialization" passed="True" timeToComplete="00:00:00.1300074" />
    <test name="PRISMMEF.Tests.Common.ViewModelBehaviorTest.TestAttach" passed="True" timeToComplete="00:00:00.0340020" />
    <test name="PRISMMEF.Tests.Common.ViewModelBehaviorTest.TestFromXaml" passed="True" timeToComplete="00:00:00.1100063" />
    <test name="PRISMMEF.Tests.Common.ViewModelProviderTest.TestConstruction" passed="True" timeToComplete="00:00:00.0630036" />
    <test name="PRISMMEF.Tests.Common.ViewModelProviderTest.TestPropertyChange" passed="True" timeToComplete="00:00:00.0520030" />
  </tests>
</StatLightTestResults>

From this, you can quickly see what I do with my Friday evenings. Seriously, it's a nice, simply, easy to iterate XML format that I can plug into my build scripts, parse with a program or even use simple XSLT and generate nice automated reports for the results of testing and even fail a build based on failed results.

Jeremy Likness

Last month, I bogged about Unit Testing ViewModels AND Views using the Silverlight Unit Testing Framework. I wanted to take that post a step further and talk about some more advanced testing scenarios that are possible.

The site itself provides a lot of information about how to get started and what is available with the framework. One thing to keep in mind that is a radical shift from other testing frameworks is that the Silverlight testing framework runs on the UI thread. This means it does not spawn multiple threads for multiple tests and in fact requires the tests to run "one at a time" so they can take advantage of the test surface that is supplied.

This is a bit different than other frameworks but in my opinion, makes a lot of sense when dealing with Silverlight. The framework provides incredible flexibility for configuring and categorizing your tests.

If you are searching for a very comprehensive example of the framework in use, look no further than the Silverlight Toolkit. This comes with all source code and in fact uses the testing framework for its tests. You will find not only advanced scenarios for testing, but thousands upon thousands of tests! (I also am guessing that a new standard for PC performance has been invented by mistake ... let's all compile the entire toolkit and compare how long it takes!)

Tagging Tests

One thing you'll find if you run the toolkit tests is that you can enter a tag to filter tests. For example, type in "Accordion" to only run the 800 or so unit tests for accordion-type controls.

To use tag functionality, simply "tag" your test like this:


[TestClass] 
[Tag("MEF")]
public class PartModuleTest 
{
}

I've tagged the test to be a MEF-related test. When I wire up the framework, I can filter the tag like this:


UnitTestSettings settings = UnitTestSystem.CreateDefaultSettings();
settings.TagExpression = "MEF";
this.RootVisual = UnitTestSystem.CreateTestPage(settings);  

When I run the tests, only my tests tagged with MEF will run! The toolkit provides an example of a UI that allows you to select the tag, then run the test.

Asynchronous Tests

It is often necessary to test methods that are asynchronous or require event coordination. An example may be a service that must wait on return values, or a user control that must be loaded into the framework before you can test it. The Silverlight Unit Testing Framework provides the Asynchronous tag to facilitate this type of test. This tells the framework not to move onto the next test nor consider the current test method complete until an explicit call to TestComplete is made.

There are several "helper" methods supplied for asynchronous processing that we'll explore in a minute. To use these methods requires inheriting from one of the base test classes such as SilverlightTest which provides the methods as well as the test surface to add controls to.

In PRISM, MEF, and MVVM Part 1 of 3: Unity Glue I explored various options for binding the view model to the view. The 3rd and final method I reviewed was using an attached behavior. I would like to write some unit tests for that behavior (indeed, if I were a test-driven development or TDD purist, I would have written those tests first).

In order to test the behavior, I need to attach it to a FrameworkElement and then validate it has done what I expected it to do. But how do I go about doing that in our unit test environment?

Attached Behaviors

Similar to other controls in other frameworks, Silverlight controls have a distinct life cycle. It varies slightly depending on whether the control has been generated in XAML or through code. There is a great summary table of these events on Dave's Blog. What's important to note is that values and properties are set as soon as you, well, set them, but bindings don't take effect until they are inserted into the visual tree. In XAML, the XAML node becomes part of the tree and fires the Loaded event once it is fully integrated. In code, this happens after the element is added as the child of some other element that is in the tree. This allows Silverlight to parse the hierarchy and propagate dependency properties.

So what we essentially want to do is take our behavior, attach it to an element, and then wait for the Loaded event to fire so we can inspect the element and see that it has been modified accordingly (in this case, we expect that the DataContext property has been set to our view model).

Setting up the Project

The testing framework provides some handy templates for getting started. I add a new project and select the Silverlight Test Project template. I then add references to the projects I'll be testing and the supporting frameworks like PRISM and MEF.

Next, I'll want to build some helper classes to help me test my functionality.

Helper Classes

I like to create a folder called Helper and place my stubs, mocks, and other helper classes there. These may be utilities, like the Exception Expected utility I use, or classes that are used for the testing framework.

First, I'll create a test view model with a simple string and string collection property for testing:


public class TestViewModel 
{
    public TestViewModel()
    {
        ListOfItems = new List<string>();
    }

    public TestViewModel(List<string> items)
    {
        ListOfItems = items;            
    }

    public string Property { get; set; }

    public List<string> ListOfItems { get; set; }
}

If my view models have common methods described in a base class or interface, I might use a mocking framework to mock the class instead.

The Test Class

The behavior I created has an affinity to the Unity inversion of control (IoC) container. It could be refactored otherwise, but it made sense for the sake of the demonstration. Therefore, I'll need to have a container for testing, as well as the view model. My test class starts out looking like this (notice I base it on SilverlightTest):


[TestClass]
public class ViewModelBehaviorTest : SilverlightTest
{
    const string TESTPROP = "Test Property";

    IUnityContainer _container;

    TestViewModel _viewModel; 

    [ClassInitialize]
    public void ClassInitialize()
    {
        _container = new UnityContainer();

        _viewModel = new TestViewModel() { Property = TESTPROP }; 
        _container.RegisterInstance<TestViewModel>(_viewModel); 

        ViewModelBehavior.Container = _container; 
    }
}

I create a reference to the entire test class for the container and the test view model. When the class is initialized (this is one-time setup, before all tests are run) I create a container, a view model, and tell the container that anytime someone asks for the view model, give them the specific instance I created. I also set the container on the type for the view model behavior class, so it knows what to use when resolving the view model.

The Code Behind Test

For my first test, I'll programmatically attach the behavior and test that it works. The view model behavior takes in a string that is the fully qualified type name for the view model, and then uses the unity container to resolve it. Therefore, my test looks like this:


[TestMethod]
[Asynchronous]
[Description("Test creating an element and attaching in code behind.")]
public void TestAttach()
{
    TextBlock textBlock = new TextBlock();
    textBlock.SetValue(ViewModelBehavior.ViewModelProperty, typeof(TestViewModel).AssemblyQualifiedName);
                
    textBlock.Loaded += (o, e) => 
    {
        Assert.IsNotNull(textBlock.DataContext, "The data context was never bound.");
        Assert.AreSame(textBlock.DataContext, _viewModel, "The data context was not bound to the correct view model.");

        EnqueueTestComplete();
    };

    TestPanel.Children.Add(textBlock);                                  
}

There's a few things going on here, so let's break them down!

The TestMethod attribute tags this method to be run by the framework. It is decorated with a description, which I can view on the output when the test is run and helps make the test more, ah, descriptive. The first thing I do is create a test block and attach the view model property. Here, I'm taking the test view model and getting the fully qualified name and using that to set the attached property. We want to make sure everything works fine and there are no errors during binding, so this is where the asynchronous pieces come into play.

The Asynchronous tag tells the framework that we're waiting on events, so don't consider this test complete until we explicitly tell the framework it's complete. When the text block fires the Loaded event, we confirm that the data context is not null and that it in fact contains the exact instance of the view model we created in the class initialization. Then we tell the framework the test is complete by calling EnqueueTestComplete, which is provided by the base class.

Finally, if you were to run this without the last line, the test would stall because the text block would never get loaded. We add it as a child of the test surface, and this injects it into the visual tree and fires the loaded event.

The XAML Test

I'm not completely confident with this test because the whole reason for creating a behavior was so I could attach the view model in XAML and not use code behind. Therefore, I should really test attaching this behavior through XAML. So, at the top of the test class we'll create the necessary XAML and wrap it in a UserControl:


const string TESTXAML = 
    "<UserControl " +
        "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" "  +
        "xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" " +
        "xmlns:vm=\"clr-namespace:PRISMMEF.Common.Behavior;assembly=PRISMMEF.Common\">" +
            "<Grid x:Name=\"LayoutRoot\" Background=\"White\" " +
                "vm:ViewModelBehavior.ViewModel=\"PRISMMEF.Tests.Helper.TestViewModel, PRISMMEF.Tests, Version=1.0.0.0\">" +
                "<ListBox x:Name=\"ListBox\" ItemsSource=\"{Binding ListOfItems}\"/>" +
    "</Grid></UserControl>";

If you think the constant is ugly, you can always add an actual XAML file, set it as an embedded resource, then read it in instead. That would give you the full functionality of the editor to tweak the test code. Here, we simply create a control with a grid and a list box. The list box uses the attached behavior and also binds the list.

I want to test the list binding as well, so I add a collection to my test class:


.
private static readonly List<string> _testCollection = new List<string> { "test1", "test2" };         
.

In the class initialize method, I'll pass this into the view model's constructor so it is set on the ListOfItems property.

Now, we can create the control from XAML, load it, and test it:


[TestMethod]
[Asynchronous]
[Description("Test creating from XAML")]
public void TestFromXaml()
{
    UserControl control = XamlReader.Load(TESTXAML) as UserControl;
    
    control.Loaded += (o, e) => 
    {
        ListBox listBox = control.FindName("ListBox") as ListBox;

        Assert.IsNotNull(listBox, "ListBox was not found.");
        Assert.IsNotNull(listBox.DataContext, "The data context was never bound.");
        Assert.AreSame(listBox.DataContext, _viewModel, "The data context was not bound to the correct view model.");

        IEnumerable<string> list = listBox.ItemsSource as IEnumerable<string>; 
        List<string> targetList = new List<string>(list); 
        CollectionAssert.AreEquivalent(targetList, _testCollection, "Collection not properly bound."); 

        EnqueueTestComplete(); 
    };

    TestPanel.Children.Add(control);           
 }

Now we load the control from XAML and wire in the Loaded event to test for the data context and the instance. Then, I take the items from the list box itself and compare them with the original list using CollectionAssert. The AreEquivalent does a set comparison. Then we signal the test is complete.

There's no code for this example because it was very straightforward and I'll likely be posting a more comprehensive example in the future as the result of a talk I'll be giving. Be sure to tune into MSDN's geekSpeak on Wednesday, February 17th, 2010 when I will be the guest to cover exclusively the topic of the Silverlight Unit Testing Framework (the talks are all stored on the site in case you read this after the event).

Thanks!

Jeremy Likness

Over the past few posts I've been exploring models for modularized Silverlight applications that follow the MVVM pattern (using Prism/CAL). In this post, I'd like to cover unit testing, and writing appropriate tests not just for the view model, but the view itself.

Before we continue, I'm going to assume you've read:

These articles form the core of what I'm about to discuss. I also want to make sure you're familiar with the Silverlight unit testing framework. You can download it and review some articles about how to use it over at the Unit Test Framework for Microsoft Silverlight page. I highly recommend pulling down the project and class templates as they will make your life easier!

The testing framework for Silverlight sets up a project that you run, and that project will then create a visual page that displays the results of tests. What's important is that the test framework will not only support class tests, but can also host controls and test the hosted controls as well. Do we even want to do this? I think so.

Set up your test project and make it the runnable one by adding a new project to your existing Silverlight solution, using the Silverlight project template, then right-clicking on the project and setting it as the start-up project.

Let's get started with a real example. I want to control the visibility of a control based on a boolean value in the view model, so I create a converter that takes in a boolean and returns visibility. I can bind the visibility like this:


<TextBlock Text="Conditional Text" Visibility="{Binding ConditionFlag,Converter={StaticResource BoolVisibilityConverter}}">

The code for the converter is simple:


public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}

To test that we get what we want, simply add a new class in your test project (use the Silverlight Test Class template). With a little bit of typing you will end up with something like this:


[TestClass]
public class BoolVisibilityConverterTest
{
    BoolVisibilityConverter _target;

    [TestInitialize]
    public void Initialize()
    {
        _target = new BoolVisibilityConverter();
    }

    [TestMethod]
    public void TestTrue()
    {
        object result = _target.Convert(true, typeof(bool), null, CultureInfo.CurrentCulture);
        Assert.IsNotNull(result, "Converter returned null.");
        Assert.AreEqual(Visibility.Visible, result, "Converter returned invalid result.");
    }

    [TestMethod]
    public void TestFalseNoParameter()
    {
        object result = _target.Convert(false, typeof(bool), null, CultureInfo.CurrentCulture);
        Assert.IsNotNull(result, "Converter returned null.");
        Assert.AreEqual(Visibility.Collapsed, result, "Converter returned invalid result.");
    }
}

Not rocket science there ... but it's nice to start out with a few green lights. When you run it, you'll see that your two tests passed and all is well (you can, of course, assert something invalid to see what a failure looks like).

Now let's test a view model. Our view model takes in a IService reference so that it can log a user in. It has bindings for username and password and a login command. The service looks like this:


public interface IService 
{
   void Login(string username, string password, Action<bool> result); 
}

So the view model looks like this:

public class ViewModel : INotifyPropertyChanged 
{
   private IService _service;

   public ViewModel(IService service)
    {
        _service = service;
       
        LoginCommand = new DelegateCommand<object>( o=>CommandLogin );            
    }  

    private bool _isDirty;

    public bool IsDirty
    {
        get { return _isDirty; }
    }

    private string _username, _password;

    public string Username
    {
        get { return _username; }
        set
        {
            if (value != null && !value.Equals(_username))
            {
                _username = value;
                OnPropertyChanged("UserName");                
            }
        }
    }

    public string Password
    {
        get { return _password; }
        set
        {
            if (value != null && !value.Equals(_password))
            {
                _password = value;
                OnPropertyChanged("Password");
            }
        }
    }

   public DelegateCommand<object> LoginCommand { get; set; }

   public void CommandLogin()
    {
        if (string.IsNullOrEmpty(_username))
        {
            throw new ValidationException("Username is required.");
        }

        if (string.IsNullOrEmpty(_password))
        {
            throw new ValidationException("Password is required.");
        }

        _service.Login(_username, _password, (result) =>
        {
            if (result)
            {
                // logic to navigate to a new page
            }
            else
            {
                throw new ValidationException("The username/password combination is invalid.");
            }
        });
    } 

    protected void OnPropertyChanged(string property)
    {            
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
        if (!_isDirty)
        {
            _isDirty = true;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs("IsDirty")); 
            }
        }
    }

    public void ResetDirtyFlag()
    {
        if (_isDirty)
        {
            _isDirty = false;
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs("IsDirty"));
            }
        }
    } 
}

Notice how properties being set should automatically set the "dirty" flag as well. I may want to bind my login button to the flag so it only becomes available when the user has changed something, for example. There is also a public method to reset the flag.

In order to satisfy my service, I'll create a "mock" object. Why a mock, and not a stub? A stub is a piece of code you put in place to allow something to happen. If I wanted to stub my service, I'd do this:


public class ServiceStub : IService
{
   public void Login(string username, string password, Action<bool> result)
   {
      result(true); 
   }
}

This would always call back with a valid user and stubs out the functionality so I don't have to implement a real login. A mock object, on the other hand, changes. To make this a mock, I do this:


public class ServiceMock : IService 
{
   public bool LoginCalled { get; set; }

   public void Login(string username, string password, Action<bool> result)
   {
      LoginCalled = true;
      result(true); 
   }
   
}

The class is a mock because it changes based on how it is used, and then we can query that change to see if our code is doing what we want. So let's set up some tests with the view model:


[TestClass]
public class ViewModelTest
{

    private ViewModel _target;
    private ServiceMock _service;

    [TestInitialize] 
    public void Initialize()
    {
        _service = new ServiceMock();
        _target = new ViewModel(_service);

    }

    [TestMethod]
    public void TestConstructor()
    {
       Assert.IsFalse(_target.IsDirty,"Dirty flag should not be set."); 
       Assert.IsFalse(_service.LoginCalled,"Login should not have been called.");
       Assert.IsNotNull(_service.LoginCommand, "Login command was not set up."); 
    }
}

You can test that the username hasn't been populated, for example. Now we can do a little more. In the example, we throw a ValidationException (a custom class) when the username is invalid. The Silverlight 3 validation framework can capture this based on data binding and show appropriate error messages to the client. We want to make sure if we try to login, we throw the exception, so we can do this:


[TestMethod]
[ExpectedException(typeof(ValidationException))]
public void TestLoginValidation()
{
   _target.CommandLogin(); 
}

Here we call the login command on the empty object and it should throw (and catch) the exception we're looking for.

Finally, to use our mock object, we can set a valid user name and password and call the login command, then verify that the mock object was called:


[TestMethod]
public void TestLogin()
{
   _target.Username = "Valid Username"; 

   //bonus test: check that the dirty flag got set
   Assert.IsTrue(_target.IsDirty, "Dirty flag was not set on update."); 

   _target.Password = "Password"; 
   _target.CommandLogin();

   Assert.IsTrue(_service.LoginCalled); 
}

After testing your view model, you can then begin to work on testing the view itself. In the "required reading" I discussed having a generic view base that would interact with a navigation manager to swap views into and out of view. The views are all contained in an ItemsControl, and register to a view change event. If the view goes out of focus, it moves to a hidden state. If the view comes into focus, it moves to a visible state. While this allows more control over the way the states appear and how to transition between states, there is also the chance someone may add a view and forget wire in the visual state groups. The VisualStateManager won't complain, but it can look ugly. We need to test for things like this!

Fortunately, the testing framework allows for us to host actual views. It provides a testing surface that we add controls to, and those controls are rendered so you can then inspect the visual tree. In this case, we want to emulate a view navigating to a new view and test that it is moved to the correct state.

Create a new test class. This time, however, we will inherit from the base class SilverlightTest which provides our class with a test panel to host controls on. The set up is a bit more involved, because we need to fold the mock services into the view model, then create the view and glue it all together.

Before we do this, we'll create a helper class called QueryableVisualStateManager. This class is one I borrowed from Justin Angel's fantastic blog post about Custom Visual State Managers. In his post, he details how to create a custom visual state manager that holds a dictionary of the control states so they can be queried later on (in case you've been pulling your hair out in frustration, the framework does not provide direct access to query the current visual state of controls).

I created the class verbatim, but don't care to use it in production code. Instead, we'll inject it in our test class. Here's the setup:


[TestClass]
public class LoginTest : SilverlightTest
{
    private Login _login;
    private ViewModel _viewModel;
    private ServiceMock _service;
    private NavigationManager _navigationManager;
    private QueryableVisualStateManager _customStateManager; 

    [TestInitialize]
    public void TestInitialize()
    {
        _login = new Login();
        
        FrameworkElement root = VisualTreeHelper.GetChild(_login, 0) as FrameworkElement;
        root.SetValue(VisualStateManager.CustomVisualStateManagerProperty, new QueryableVisualStateManager()); 

        _service = new ServiceMock();
        _navigationManager = new NavigationManager();
        _viewModel = new ViewModel(_service);
        _viewModel.Navigation = _navigationManager;
        _login.DataContext = _viewModel;
        TestPanel.Children.Add(_login);
    }
}

What happened? Login is my user control ... it is the view I inject into the shell to show the login page. Here I create an instance of it. Then, I use my friend the VisualTreeHelper to parse the the first child, which is going to be the grid or stack panel or whatever "host" control you have inside your user control. Then, I simply set the attached property for the custom view manager to point to the queryable helper class. This will ensure any visual state transitions are recorded in the internal dictionary. Then I wire up my mocks, databind, and finally add the login control to the TestPanel. It now gets hosted on a real test surface and can initialize and display.

Let's assume that the navigation manager I injected is responsible for swapping the view state of the control. The control goes into a HideState when not visible and a ShowState when visible. What I want to test is a simulated login command. We already tested this in the view model, so we can be confident it is going to hit the service and do what it is supposed to do. There is a piece of code that then calls the navigation manager and changes the control's state to hidden. We want to test that this hook actually gets fired when the user clicks login, so the login view disappears. Here's how:


[TestMethod]
public void TestLogin()
{
    const string SHOWSTATE = "VisualStates.ShowState";
    const string HIDESTATE = "VisualStates.HideState";

    // set up this view
    _navigationManager.NavigateToPage(NavigationManager.NavigationPage.Login);
                
    string state = QueryableVisualStateManager.QueryState(_login);
    Assert.IsTrue(state.Contains(SHOWSTATE) && !state.Contains(HIDESTATE), "Invalid visual state."); 

    // trigger login 
    _viewModel.Username = "user";
    _viewModel.Password = "password";
    _viewModel.CommandLogin();
   
    state = QueryableVisualStateManager.QueryState(_login);
    Assert.IsTrue(state.Contains(HIDESTATE) && !state.Contains(SHOWSTATE), "Invalid visual state."); 
}

We first test the pre-condition by navigating to the login page and confirming it has the ShowState and not the HideState. Then, we simulate a login action (this is why command binding and view models are so powerful) and query the state again, testing to make sure we went into a hidden state.

When you run this test, you might actually see the control flicker for a moment on the screen as it gets initialized on the test surface before it is manipulated and then discarded for other tests. With the right architecture, you are now able to test from the view down to the backend services that drive your application. Now that's powerful!

Jeremy Likness