Functional testing of a MVVM Silverlight application with Fitnesse
MVVM is a great pattern to enable (among other things) unit testing of a XAML based application GUI. If you’re not familiar with it, this article explains it well and describes its use with Greenpepper on a real life project.
Functional testing works great with MVVM, but several issues prevent the use of functional testing tools (e.g. Fitnesse) with a Silverlight project out of the box.
If the previous article convinced you to implement automated functional testing on your application, but its GUI is in silverlight instead of WPF, let’s see how you can circumvent those issues.
The following has been implemented with Fitnesse, but should also work with Greenpepper or any other .Net automated testing framework.
How can Fitnesse load Silverlight code ?
Loading silverlight code in a standard .Net CLR is a matter of referencing the proper assemblies. Since the assemblies needed to load a ViewModel have the same name than .Net counterparts, Visual Studio does not allow to add them directly (it replaces it with the .Net assembly of the same name found in the GAC).
So this requires some .csproj editing, as such :
<Reference Include="System.ServiceModel">
<HintPath>..\DLLs\System.ServiceModel.dll</HintPath>
</Reference>
Silverlight assemblies must be referenced with their location on the filesystem. The assemblies required to load a View Model are System.ServiceModel, System.Windows, System.Runtime.Serialization, System.Xml, and System.Xml.Linq.
Add those assemblies as references in your Visual Studio project holding your fixtures, as well as references to your Silverlight projects in your solution, and you’re good to go.
What if my view model calls a WCF service ?
Now we can call silverlight code from fitnesse. But if you’re writing a Silverlight application, chances are it is calling WCF services to do some work server-side. You can’t directly inject a WCF service implementation into a view model, since a WCF client proxy is generated to call it. Moreover, the client side interface only exposes asynchronous methods.
So the challenge is to be able to transform this :
// Server side WCF Service signature
int DoSomeWork(int i);
into these :
// Client side equivalent generated by Visual Studio
IAsyncResult BeginDoSomeWork(int i, AsyncCallback callback, object asyncState);
int EndDoSomeWork(IAsyncResult result);
Those are standard asynchonous methods any delegate can produce. A wrapper class can be created to translate the server-side service into the client-side one this way :
public class MyServiceWrapper : ClientSideNamespace.IService // Client-side interface {
private ServerSideNamespace.IService service;
private Func<int, int> SomeWorkDelegate;
public MyServiceWrapper(ServerSideNamespace.IService service) // Server-side interface {
this.service = service;
this.SomeWorkDelegate = i => service.DoSomeWork(i);
}
public IAsyncResult BeginDoSomeWork(int i, AsyncCallback callback, object asyncState) {
return SomeWorkDelegate.BeginInvoke(i, callback, asyncState);
}
public int EndDoSomeWork(IAsyncResult result) {
return SomeWorkDelegate.EndInvoke(result);
}
}
Use this wrapper as a service implementation in your ViewModel and you’re good to go.
What if my WCF service returns more than an integer ?
Just like method signatures differ between client and server side, data structures are not the same. Properties have the same name, but types can differ, especially Collections implementations. Automapper is an open source library able to solve this issue in a very convenient way, enabling the wrapper to translate a server-side dto into a client-side dto and vice versa.
Assuming the WCF service evolves to :
DoSomeWorkDto DoSomeWork(int i);
The wrapper becomes :
public class MyServiceWrapper : ClientSideNamespace.IService // Client-side interface {
private ServerSideNamespace.IService service;
private Func<int, ClientSideNamespace.DoSomeWorkDto> SomeWorkDelegate;
public MyServiceWrapper(ServerSideNamespace.IService service) // Server-side interface {
this.service = service;
this.SomeWorkDelegate = i => Mapper.Map<ServerSideNamespace.DoSomeWorkDto, ClientSideNamespace.DoSomeWorkDto>(service.DoSomeWork(i));
}
public IAsyncResult BeginDoSomeWork(int i, AsyncCallback callback, object asyncState) {
return SomeWorkDelegate.BeginInvoke(i, callback, asyncState);
}
public ClientSideNamespace.DoSomeWorkDto EndDoSomeWork(IAsyncResult result) {
return SomeWorkDelegate.EndInvoke(result);
}
static MyServiceWrapper() {
Mapper.CreateMap<ServerSideNamespace.DoSomeWorkDto, ClientSideNamespace.DoSomeWorkDto>();
}
}
The Mapper class is pretty straightforward, just call the CreateMap method for all dto class couples (both ways if necessary). Then include a Mapper.Map call in your delegates in the wrapper and you’re good to go.
Conclusion
The practice of testing an application with Fitnesse (or any functional testing tool) through its ViewModels is really valuable. Matthieu’s feedback was already self-explanatory about this. Not being able to achieve it on a Silverlight application would have been a shame.
At the price of a little development overhead (the WCF services wrappers), this practice is applicable on Silverlight projects too.
A recent experience with a Silverlight application developed by Octo showed that this overhead is negligible compared to the benefits of automated functional testing involving the ViewModels.