Unit Testing with WPF + MVP  
Author Message
Kent Boogaart





PostPosted: Windows Presentation Foundation (WPF), Unit Testing with WPF + MVP Top

Hi,

I'm trying to suss out the best way to unit test presenters with WPF views in a multithreading scenario. This is easiest to explain via code. Here's a view interface:

public interface ISearchView
{
Dispatcher Dispatcher
{
get;
}

SearchCriteria SearchCriteria
{
set;
}

SearchResults SearchResults
{
set;
}

event EventHandler<EventArgs> PerformSearch;
}

The implementation of this interface is a WPF user control that binds various child controls to the search criteria to enable the user to edit the criteria prior to searching. The PerformSearch event is raised whenever the user clicks the search button. The Dispatcher property gets the view's dispatcher so the presenter can pass results back to it safely.

The presenter code looks something like this:

public class SearchPresenter
{
private readonly ISearchView _view;
private readonly SearchCriteria _searchCriteria;

public SearchPresenter(ISearchView view)
{
_searchCriteria = new SearchCriteria();
_view = view;
_view.SearchCriteria = _searchCriteria;
_view.PerformSearch += View_PerformSearch;
}

private void ViewPerformSearch(object sender, EventArgs e)
{
DoSearch();
}

private void DoSearch()
{
_view.Results = null;

ThreadPool.QueueUserWorkItem(delegate
{
//search logic is here - it might take a while to execute

//search is finished - assign results to view
_view.Dispatcher.Invoke(DispatcherPriority.Send, new AssignHandler(Assign), results);
});
}
}

This all works fine and the beauty is that the view has no idea that the search is taking place on a separate thread. It doesn't need to know. We could change the presenter so that it is single-threaded or only switches to a separate thread in certain circumstances and the view would be none the wiser. Also, the view code is kept much simpler as a result.

The problem occurs during unit testing and, specifically, mocking the view's interface. The Dispatcher class is sealed and only has private constructors. The only way to get a Dispatcher is via the static CurrentDispatcher property. This makes it extremely cumbersome and hard, if not impossible, to unit test this code.

I have thought of only a couple of workarounds:

  1. Put the thread-safety code into the view implementation, and just have the presenter assign the results directly rather than via the dispatcher.
  2. Define my own IDispatcher interface and two implementations of this interface: DispatcherWrapper and MockDispatcher. DispatcherWrapper would wrap WPF's Dispatcher class and MockDispatcher would be used in unit testing. Views would expose an IDispatcher instead of a Dispatcher.

I don't like option 1 because it complicates the view implementation and requires it to understand the threading context in which it is running. I don't like 2 because, well, it's ugly and requires more work.

Any help much appreciated.

Thanks,
Kent Boogaart



Visual Studio 20084