Browse by Tags

All Tags » mocking   (RSS)

In an interview earlier this year with MSDN geekSpeak, I discussed unit testing for Silverlight and some of the frameworks that are available. One audience member raised a very important question: "How do we test the XAML?" Specifically, what happens when we hand off XAML to a designer or another developer, and they accidently remove a data-binding or other critical element, then pass it back to us?

The Problem

Many developers don't realize this, but the view is not decoupled from the underlying code. Unless you are using a convention-based approach (and then an affinity still exists, albeit expressed via the convention), you are likely either wiring in events and managing the view from code-behind, or using data-binding to bind a view to an underlying view model or binding model. One mistake people tend to make is the assumption that the view is completely decoupled from the view model.

The truth is, the data-bindings are a double-edged sword. First, make no mistake, you are explicitly referring to a contract when you specify data-binding. You might not need to know the specific type of the underlying data context, but you are pointing to specific sources and property paths on "some object" that must be satisfied. The "double-edge" is that the data-binding framework will silently swallow any exceptions if you happen to bind to the wrong path. Fat-finger "country" as "county" and you may find a big blank label appearing where you were hoping to see "United States."

Even more likely is the fact that often you may have a designer creating XAML assets, an integrator moving those assets into the project and then a developer working on the actual code. At any phase of the hand-off, someone might get fancy and decide to replace a combo box with a list box and forget to update the data-bindings. The compiler won't complain at all, because there is no check for the absence of data-binding, so you'll likely not catch the error until you begin testing the application.

The Solution

While there is no easy way to "type" the view and force the compiler to emit errors when the data-binding is incorrect, you can create unit tests on those views to test the expected bindings. You can also test for attached behaviors and other artifacts in the XAML that are expected for the application to run successfully.

Let's take a look at a simple view model I like to use when demonstrating the Model-View-ViewModel (MVVM) pattern. I call it Cascadia because it facilitates the classic case of cascading dropdowns. The view model sits on top of a service for fetching countries and states or provinces, that is injected via the Managed Extensibility Framework. MEF is outside the scope of this post, and we won't need it for testing anyway because we'll mock the dependencies. Here is my view model:

[Export]
public class CascadiaViewModel : INotifyPropertyChanged, IPartImportsSatisfiedNotification 
{
    [Import]
    public IAddressService AddressService { get; set; }

    public CascadiaViewModel()
    {
        Countries = new ObservableCollection<Country>();
        States = new ObservableCollection<State>();

        if (!DesignerProperties.IsInDesignTool) return;

        // design-time controls

        var country = new Country {CountryCode = "US", CountryName = "United States"};
        var state = new State {StateCode = "GA", StateName = "Georgia", StateCountry = country};
        Countries.Add(country);
        States.Add(state);
        CurrentCountry = country;
        CurrentState = state;
    }

    public ObservableCollection<Country> Countries { get; set; }

    private Country _country;

    public Country CurrentCountry
    {
        get { return _country; }
        set
        {
            _country = value;
            _UpdateStates();
            _RaisePropertyChanged("CurrentCountry");
        }
    }

    private void _UpdateStates()
    {
        if (DesignerProperties.IsInDesignTool)
        {
            return;
        }

        States.Clear();
        AddressService.GetStatesForCountry(CurrentCountry.CountryCode, states=>
           {
              foreach(var state in states)              
              { States.Add(state); }
              CurrentState = States[0];
           });
    }

    public ObservableCollection<State> States { get; set; }

    private State _state;

    public State CurrentState
    {
        get { return _state; }
        set
        {
            _state = value;
            _RaisePropertyChanged("CurrentState");
        }
    }

    private void _RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnImportsSatisfied()
    {
        AddressService.GetCountries(countries =>
        {
            foreach (var country in countries)
            {
                Countries.Add(country);
            }
            CurrentCountry = Countries[0];
        });
    }
}

Notice that I am providing some design-time support right in the view model so it will appear in the designer when a view is databound. There may be some arguments about the concept of a "designer" leaking into my view model, but in my opinion, the view model is specific to views. It is not "business logic" but an entity responsible for coordinating the hand-off between underlying business logic and the view itself. Therefore, why not have the intelligence to provide some sample data during design time?

The behavior is straightforward. We populate a list of countries, synchronize a default country, then populate a list of states for the selected country and synchronize a default state. The expected behavior is that I can change the selected state, and when I change the selected country, my state list is refreshed and a new default picked. All of this can be tested before we even worry about the service or the view, in my opinion one of the advantages of the MVVM pattern.

Next, let's take a look at the XAML for a view that binds to the view model. Here is the markup:

<UserControl x:Uid="UserControl_1" x:Class="Cascadia.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"
   mc:Ignorable="d" 
   d:DesignHeight="300" 
   d:DesignWidth="400">
  <Grid x:Uid="LayoutRoot" x:Name="LayoutRoot" 
      Background="White" DataContext="{Binding Source={StaticResource VMLocator},Path=Cascadia}">
    <Grid.ColumnDefinitions>
      <ColumnDefinition x:Uid="ColumnDefinition_1" Width="Auto" />
      <ColumnDefinition x:Uid="ColumnDefinition_2" Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition x:Uid="RowDefinition_1" Height="Auto" />
      <RowDefinition x:Uid="RowDefinition_2" Height="Auto" />
      <RowDefinition x:Uid="RowDefinition_3" Height="Auto" />
      <RowDefinition x:Uid="RowDefinition_4" Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock x:Uid="TextBlock_1" Text="Select Your Country:" Grid.Row="0" Grid.Column="0" AutomationProperties.AutomationId="TextBlock_1" />
    <ComboBox x:Uid="cbCountries" x:Name="cbCountries" Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Countries}" SelectedItem="{Binding CurrentCountry,Mode=TwoWay}" DisplayMemberPath="CountryName" />
    <TextBlock x:Uid="TextBlock_2" Text="Select Your State:" Grid.Row="1" Grid.Column="0" AutomationProperties.AutomationId="TextBlock_2" />
    <ComboBox x:Uid="cbStates" x:Name="cbStates" ItemsSource="{Binding States}" SelectedItem="{Binding CurrentState,Mode=TwoWay}" Grid.Row="1" Grid.Column="1" DisplayMemberPath="StateName" />
    <TextBlock x:Uid="TextBlock_3" Text="Selected Country:" Grid.Row="2" Grid.Column="0" AutomationProperties.AutomationId="TextBlock_3" />
    <TextBlock x:Uid="tbSelectedCountry" x:Name="tbSelectedCountry" Text="{Binding Path=CurrentCountry.CountryName}" Grid.Row="2" Grid.Column="1" Height="16" VerticalAlignment="Bottom" />
    <TextBlock x:Uid="TextBlock_4" Text="Selected State:" Grid.Row="3" Grid.Column="0" AutomationProperties.AutomationId="TextBlock_4" />
    <TextBlock x:Uid="tbSelectedState" x:Name="tbSelectedState" Text="{Binding Path=CurrentState.StateName}" Grid.Row="3" Grid.Column="1" />
  </Grid>
</UserControl>

This basically shows two drop-downs, with two labels that synchronize with the selected items. The "affinity" or "coupling" is introduced when we specify a data-binding path and expected something specific, such as CurrentState.StateName, to be present and correct. Our application is not functioning correctly if these bindings don't work.

If you're wondering about the Uid and AutomationProperties, both are important for globalization/localization as well as accessibility. In fact, I'm excited to be on one of the teams that is previewing UI Automation for Silverlight. This allows recording and/or creating coded UI tests (similar to WPF) and running/testing those against Silverlight applications. I've been very pleased with what the tool can do so far and am excited about the upcoming release to the public (this is not the same as the "manual" automation that I blogged about here.)

The Test

Now we can get down to writing a test to ensure that the bindings are working properly. In The Art of Unit Testing author Roy Osherove lists several properties of a good unit test. Two of those include it should run at the push of a button and it should run quickly. In this case, the workflow is that we receive XAML from a designer or integrator. Upon checkin, either we have an automated build process that runs our unit tests automatically, or we pull it down and as a manual process set the test page as the startup page and hit F5 to run the tests. Either way, we can check very quickly whether or not our bindings were preserved.

What does a test look like? In the setup for our test, we'll mock out the service and specify the countries and states we want. I'll also override the view locator specified in XAML and directly bind to the view model for our test. This is the test initialize method:

private MainPage _target;
private CascadiaViewModel _viewModel;
private Mock<IAddressService> _service;

private Country[] _countries;
private State[] _states;

[TestInitialize]
public void TestInit()
{
    var us = new Country {CountryCode = "US", CountryName = "United States"};
    var georgia = new State {StateCode = "GA", StateCountry = us, StateName = "Georgia"};
    var mexico = new Country {CountryCode = "MX", CountryName = "Mexico"};
    var oaxaca = new State {StateCode = "OA", StateCountry = mexico, StateName = "Oaxaca"};

    _target = new MainPage();

    _countries = new[] {us, mexico};
    _states = new[] {georgia, oaxaca};

    _viewModel = new CascadiaViewModel();

    _service = new Mock<IAddressService>();
    _viewModel.AddressService = _service.Object;

    _service.Setup(s => s.GetCountries(It.IsAny<Action<IEnumerable<Country>>>()))
        .Callback((Action<IEnumerable<Country>> action) => action(_countries));

    _service.Setup(s => s.GetStatesForCountry(It.IsAny<string>(), It.IsAny<Action<IEnumerable<State>>>()))
        .Callback(
            (string countryCode, Action<IEnumerable<State>> action) =>
            action(from s in _states where s.StateCountry.CountryCode.Equals(countryCode) select s));

    GetUiElement<Grid>("LayoutRoot").DataContext = _viewModel;
}

private T GetUiElement<T>(string name) where T : UIElement
{
    return (T) _target.FindName(name);
}

Notice at this point we are just setting up the mocks and data-binding the view model. Next, we'll test the actual bindings:

[Asynchronous]
[TestMethod]
public void TestCountrySelection_UpdatesViewModelAndDataBindings()
{
    _target.Loaded +=
        (o, e) =>
            {
                _viewModel.OnImportsSatisfied(); // set this up

                var comboBox = GetUiElement<ComboBox>("cbCountries");
                var stateComboBox = GetUiElement<ComboBox>("cbStates");
                var textBlock =
                    GetUiElement<TextBlock>("tbSelectedCountry");
                var stateTextBlock =
                    GetUiElement<TextBlock>("tbSelectedState");


                var defaultStates = from s in _states
                                    where
                                        s.StateCountry.CountryCode.Equals(
                                            _countries[0].CountryCode)
                                    select s;

                // defaults
                Assert.AreEqual(_countries[0], _viewModel.CurrentCountry,
                                "Country combo box failed to initialize current country.");
                Assert.AreEqual(_countries[0].CountryName, textBlock.Text,
                                "Country combo box failed to initialize the text block.");
                Assert.AreEqual(_states[0], _viewModel.CurrentState,
                                "Failed to initialize current state.");
                Assert.AreEqual(_states[0].StateName, stateTextBlock.Text,
                                "Failed to initialize the state text block.");

                CollectionAssert.AreEquivalent(comboBox.Items, _countries,
                                                "Failed to data-bind countries.");
                CollectionAssert.AreEquivalent(stateComboBox.Items,
                                                defaultStates.ToArray(),
                                                "Failed to data-bind states.");
                        
                comboBox.SelectedItem = _countries[1];

                var mexicoStates = from s in _states
                                    where
                                        s.StateCountry.CountryCode.Equals(
                                            _countries[1].CountryCode)
                                    select s;

                // defaults
                Assert.AreEqual(_countries[1], _viewModel.CurrentCountry,
                                "Country combo box failed to update current country.");
                Assert.AreEqual(_countries[1].CountryName, textBlock.Text,
                                "Country combo box failed to update the text block.");
                Assert.AreEqual(_states[1], _viewModel.CurrentState,
                                "Failed to update current state.");
                Assert.AreEqual(_states[1].StateName, stateTextBlock.Text,
                                "Failed to update the state text block.");

                CollectionAssert.AreEquivalent(stateComboBox.Items,
                                                mexicoStates.ToArray(),
                                                "Failed to update data-binding for states.");

                EnqueueTestComplete();
            };

    TestPanel.Children.Add(_target);
}

We are doing a few things here. Unit tests follow the pattern: arrange, act, assert. I am arranging the view model and services in the beginning. Note that we wait until the target view is loaded before acting on it, so that data-binding has a chance to take effect. We are placing the view on a test surface, but tools like StatLight can effectively mock the surface to allow the tests to be run offline in an automated fashion. The test is asynchronous because we must wait for the loaded event to fire before acting and asserting, and the last step we do is add the view to the test surface.

When the view is loaded, I'm first testing some pre-conditions. These are the default bindings we'd expect from the view model being initialized. Then, I change the selection and assert that the changes happened as expected.

This test will function on several levels. First, because I'm grabbing controls by name, if the names change (for example, we change a combo box to a list box and change the name to "lbCountries") then the test will fail. If I don't have an affinity for named controls (i.e. everything happens through databinding) then I will change my strategy to use the automation id. I'll call the control something generic like "CountryList" and will find it regardless of the control type or name.

Second, we have some very specific behaviors we expect, such as changing a country and having the state list and default state update as well. This is fully tested and if any of the data-bindings are broken, the test will fail. I can quickly determine if the XAML was corrupted and fix the problem before it gets into production. I think most developers will agree that the easiest way to fix a bug is to find it as close to the source as possible.

What if I needed to test a custom control, or even do something simple like emulate a button click to test data-binding to an ICommand object? No problem. This is where we would use automation peers. For example, to simulate a button click, I can include the following code:

var btn = GetUiElement<Button>("btnCommand");
var btnPeer = new ButtonAutomationPeer(btn);
btnPeer.Click();

The above code will simulate a button click, and then I can test my command to ensure it fired correctly. For custom controls, you can provide your own automation peer, which is a good idea anyway for accessibility.

Conclusion

Hopefully this article demonstrated another way to catch issues fast, close to the source and before the code even makes it to your QA machine. Indirectly, I've shown how MVVM can improve the development process through both testability and workflow (i.e. being able to work on independent pieces, including XAML and view logic, separately). You also witnessed how unit testing provides value to the development process and why most of the time the net impact is faster time to "production ready" in spite of the overhead of writing tests.
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

Windows Workflow Foundation (WWF) is a powerful programming model and designer for workflow processes. Using workflow is easier than some may believe.

I wanted to share a quick post relative to some practices I've found useful for sequential workflows, specifically around Inversion of Control (IoC) and unit testing.

In our shop we have several complex algorithms that are great candidates for sequential workflow. By using sequential workflow, we can:

  • Easily visualize the overall layout and flow of the process
  • Test the architecture of the flow (i.e. do we get to this node or that node) without having to worry with or deal with the underlying implementation of nodes within the flow
  • Refactor complex code simply by dragging and dropping nodes in the designer
  • Setup unit tests to ensure the integrity of the workflow persists as other systems are refactored

If you aren't familiar with workflow, I'd suggest searching for a few tutorials or walkthroughs. This is one of those technologies that is probably easier to learn by building some test projects than it is simply reading about it. The scope of this article will be how to build your sequential workflows for unit tests.

Interfaces and Delegates In

The workflow model lets you declare public properties on the main workflow that are then available to all of the nodes within that workflow. When you instantiate the workflow, you can send in a collection of name-value pairs map to public properties. For example, if I have an interface declared on my workflow:

...
public IMyInterface MyInterfaceImplemented { get; set; }
...

Then I can pass to workflow an instance of that interface like this:

...
Dictionary<string, object> myParams = new Dictionary<string, object>
   {
      {"MyInterfaceImplemented", new MyInterfaceImplementation()}
   };
...
_runtime.CreateWorkflow(typeof (MyWorkflow), myParams);

I'll get to what _runtime is in a bit. My point is, however, that any type of business logic you follow within your workflow should be hidden behind an interface and/or delegate. If you are passing in concrete instances, you are missing out on the power of being able to unit test your workflow structure.

You may have noticed that the code blocks in a sequential workflow, unless encapsulated as a custom entity, are actually events triggered by the workflow engine. For example, I might insert a Code workflow activity called AnalyzeUser. In the code behind, this appears as:

private void AnalyzeUser_ExecuteCode(object sender, EventArgs e)
{
}

In some cases you might be calling a method or service on an existing interface. However, other cases may be simple snippets of code. In order to keep your workflow completely pluggable, consider using a delegate. For example, if the analyze user takes a user parameter and then sets a flag in the workflow based on the result, instead of this:

private void AnalyzeUser_ExecuteCode(object sender, EventArgs e)
{
   _isOver30 = User.Age > 30;            
}

Try this:

// declare a delegate to analyze the user
public delegate bool AnalyzeUserDelegate(User user); 

// declare a method to set the delegate
public AnalyzeUserDelegate AnalyzeUserMethod { get; set; }

private void AnalyzeUser_ExecuteCode(object sender, EventArgs e)
{
   _isOver30 = AnalyzeUserMethod(User); 
}

Note we've encapsulated the action that is required (set a flag by analyzing the user) but we've removed the dependency of a concrete implementation. Why would I want to do this? Perhaps I am testing the overall workflow structure and want to know when it reaches the call to the delegate. I'm not concerned about whether it sets the users age, only if the method is reached. I can easily test for that situation like this:

...
bool delegatedCalled = false;

AnalyzeUserDelegate testMethod = (user) =>
   {
      delegatedCalled = true;
      return true;
   };

myParams.Add("AnalyzeUserMethod", testMethod);
...
instance.Start(); // start the worfklow
Assert.IsTrue(delegateCalled, "The method was invoked."); 
...

This allows you to separate testing the logic/flow of the workflow from the implementation of the various nodes within the workflow.

Properties Out

We talked about how to get implementation into the workflow, now let's talk about what to get out. Even if your workflow does not "return" a value to the outside world, you should consider exposing some properties to indicate key milestones within the workflow. One of our workflows involves assigning an asset to a location. The workflow itself only needs to perform the actual assignment. There is no "output" other than the changes to the system itself. However, for testing purposes, we expose certain values such as the location assigned and a flag that indicates whether an assignment was successful. This allows us to test the outcome, like this:

...
public bool WasAssigned { get; set; }
...
instance.Start(); // start the workflow
Assert.IsTrue((bool)results["WasAssigned"]); 

That example is a simple test of whether or not a successful assignment took place.

Wiring the Tests

One thing I've noticed is that few people realize workflows are very easy to test. There are many ways to trigger a workflow (events, schedules, etc). The standard examples I've seen online involve launching the engine in potentially a different thread altogether. Fortunately, the engine is extensible and there is a service shipped with the runtime that allows you to run it in an almost-synchronous way.

The first thing to do is set up references to the run time and the service that allows for the immediate workflow execution:

...
private WorkflowRuntime _runtime; 
private ManualWorkflowSchedulerService _scheduler; 
...

In your test setup, you'll instantiate the runtime and add the manual service:

[TestInitialize]
public void TestInitialize()
{
   _scheduler = new ManualWorkflowSchedulerService(); 
   _runtime = new WorkflowRuntime(); 
   _runtime.AddService(_scheduler); 
}

Be sure to tear down the workflow after the test is run:

[TestCleanup]
public void TestCleanup()
{
    if (_runtime != null && _runtime.IsStarted)
    {
        _runtime.StopRuntime();
    }

    if (_runtime != null)
    {
        _runtime.Dispose();
    }
}

Now you can wire up your test. If you want to be able test the output results as I mentioned above, you need to bind to the WorkflowCompleted event:

...
Dictionary<string, object> results = null;
_runtime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs wce) { results = wce.OutputParameters; };
...

This will take all public properties and dump them by name and value into the results variable for inspection. The next thing is simply to create an instance and run it, like this:

WorkflowInstance instance = _runtime.CreateWorkflow(typeof (MyWorkflow), myParams);
instance.Start();
ManualWorkflowSchedulerService schedulerService = _runtime.GetService<ManualWorkflowSchedulerService>();
schedulerService.RunWorkflow(instance.InstanceId);
Assert.IsNotNull(results);

The results test ensures the workflow successfully ran.

Now I can test my workflow structure using a mocking framework like Moq. Moq makes it easy to inject a test object and verify whether or not it was called. If I have an interface called IMyUserServices and I am expecting the workflow to call a method called ValidateUser, I would simply load it up like this:

Mock<IMyUserServices> myUserServices = new Mock<IMyUserServices>(); 
Dictionary<string, object> myParams = new Dictionary<string, object> 
   {
      { "MyUserServicesImplemented", myUserServices.Object }
   };
// set up the call to always return true
myUserServices.Setup(svc => svc.ValidateUser(It.IsAny<User>())).Returns(true); 
...
instance.Start();
...
// make sure we called it
myUserServices.Verify(svc => svc.ValidateUser(It.IsAny<User>()), Times.Once());
...

Obviously going through all of the features and functionality of mock frameworks is outside of the scope of this post, but I wanted to share how easy these tools make it to create powerful, granular tests. I am able to wire up the entire complex workflow and test that the flow works as expected before every writing a line of actual implementation. Then, it becomes simple to implement the code and write unit tests for each atomic piece of functionality. This then makes it easy to test and implement complex solutions by breaking them into simple parts.

Finally, I'll leave you with a little snippet of unit testing wisdom I recently learned. A stub is something you inject to make a test run. A mock is something you check the state of to validate your test. Often people refer to stubs as mocks, but if you aren't inspecting the stub for success, it's a stub. If you are checking it for something (state, output, exception) then it is a mock.

Jeremy Likness