Design your Silverlight application for TDD !

There is one major flaw you must have encountered whilst working with Silverlight for a while: its incompatibility with unit tests! Unless you’ve been using Silverlight solely for drawing circles and rectangles, surely you must have tried to use the Silverlight Toolkit unit test project template to try to put some TDD in your project ! …most probably you were disappointed by it because it’s fairly poor…

  • This project is specific to Silverlight (the Microsoft test assembly is specific)
  • Running tests is only possible by launching the test application wrapping up your test classes. And let’s be frank, the usability of this interface is quite poor. There is no integration in Visual Studio.
  • It’s impossible to properly analyze the tests results and metrics or even to navigate through tests and code like you’d want to.
  • It’s also impossible to run a specific test or test class without having to pollute your tests with additional tags. And then you will still have to run the application to see it play the selected tests.
  • It’s almost impossible (or fairly complicated) to integrate those tests in your continuous integration build process. Statlight (an open source project) is trying to provide a way out but this remains highly dependent on your configuration, and frankly, i never had it working on a TFS build. (this can be explained by the fact that it still needs to open a window to run your tests while your build process is highly relying on commands only)

All those issues can find an explanation in the fact that the Silverlight framework is a subset of the .NET one making them incompatible with each other.

However, even though these frameworks are different, they’re also very similar. Thanks to this, we will be able to go around the limitation stated above and set up a solution to properly unit test our Silverlight libraries. This solution relies on two parts: structure of the Silverlight projects and then unit testing them within the visual studio framework.

 

First, architecture your projects

One of the major secrets of a long running application resides in its architecture. This goes the same for the GUI (Graphical User Interface). We’re often tempted to consider the GUI as a whole monolithic bloc:

“GUI is easy, not complex enough to structure it”
“anyway, if I decide to change my user interface, I’ll probably change the whole layer, so it’s ok to mix everything here”

Good practices don’t stop at the service layer ! A good structured GUI will allow you to optimize its testability while abstracting models from views. I’m not here to remind you of the MVVM pattern, the idea here is to go one step further by physically abstracting the different parts to leverage flexibility.

I’ll be taking the example of an application exposing web services to a Silverlight light client. (It could as well be a Silverlight only application, its structure would remain the same).

Silverlight projects architecture
Silverlight projects architecture

The above architecture is composed of 3 RIA projects and 1 Web project:

Octo.Bank.Web.Ria.Views

    This library holds (like you could guess) the application views, either controls or pages. This will help us isolate the GUI behaviors (you know, the dirty fixes you do to please the user). All references to converters or ViewModels will be handled through Binding to “StaticResources”.

Octo.Bank.Web.Ria.ViewModels

    Here, we’ll isolate the GUI intelligence (or even business rules) using ViewModels, or also converters for example. We’ll also add the service references to this project (proxy generation) because this is what our models will use to manage data. If you could test only one project, this is THE library you’d want to test !

Octo.Bank.Web.Ria.Main

    This is our main application, and actually the only “Silverlight Application” project. It references the other libraries and will use them through application resources (App.xaml). To be able to run the application without issues, the trick here is to add the ServiceReferences.ClientConfig of the ViewModels project as a link in order to have the service information at runtime. Without this, your app will start and crash at the first service client instantiation, the service references not being present in the application.

Octo.Bank.Web

    The Web project is exposing our web services (of course tested as well :)). It also exposes one xap file : the main Silverlight project (which will contain the two other libraries).

 

Then, unit test Silverlight in Visual Studio

Now that we structured our application, we can clearly identify the critical library that needs testing: ViewModels. Because this is a sensible library, we want to take advantage of the Microsoft unit test framework of VS 2010, for all the reasons I mentioned earlier. Here follows, imho, one of the most clean way to do so:

1. Create a standard .NET unit test project

2. Remove all the dll references except ~QualityTools.UnitTestFramework reference.

3. Add the following references using the browser to get them from the Silverlight SDK folder you’re using (ex.: C:\Program Files (x86)\Microsoft Silverlight\5.0.60401.0)

  • system.dll
  • System.Core.dll
  • System.Windows.dll
  • System.ServiceModel.dll

and activate the library local copy, this will force the test framework into using them instead of the default .NET ones.

4. Add your favorite tools libraries (RhinoMocks.. Moq…) in their Silverlight version.

5. Add the Silverlight libraries you want to test, here Octo.Bank.Web.Ria.ViewModels

Unit test project local copy of DLLs
Unit test project local copy of DLLs

Congrats, You’ve just made this unit test library running with the VS 2010 Unit Test framework under a Silverlight runtime!

 

Continuous Integration & Code Coverage

You are nearly there, almost ready to start developing (yes, because you’re using TDD remember ? :) ! A couple of things left to do to make sure you maximize the use of the framework:

1. Add your test library to your CI build

Using TFS up to 2008 <TestContainer Include= »$(OutDir)\%2aTests.dll » />

2. Activate code coverage metrics for your tested DLL

Using VS2010, open local.testsettings, go to Data & Diagnostics, check the Code Coverage option and via Configuration, select your Silverlight ~Views assembly.

 

In conclusion

We know how much a testing framework impacts the development life-cycle. A bad productivity tool (like the SL Toolkit way of testing) and your whole TDD cycle (red, green, red, green…) is jammed ! This is why, even if this solution has an additional cost (manually referencing libraries), I find it an acceptable one when I compare it to the shift in efficiency I get in my every day job. And this is without mentioning the comfort of having the CI build run the tests and the code coverage metrics …

8 commentaires sur “Design your Silverlight application for TDD !”

  • Your solution is quite correct, but I would add the fact that you can also test view specific pages with the silverlight toolkit, and run the tests in browser. It's really the only way I found to automatically test the relation between the views and the view models. When you test a view the system obliges you to do a lot of thinks so you could expose the needed view information for testing. Also I am very curious how you test without Silverlight Toolkit the asynchronous calls from the view models to the domain service. I did not see much about testing the DomainService, that has its particularities because you need to insert a layer so you could remove the high coupling between the DomainService and Entity Framework. This can be especially tough.
  • Hi Adrian, You're right, the Silverlight Toolkit can still be used to test View related scenarios. What I wanted to show here is a way of testing SL libraries with our most efficient tools for that (VS testing framework). About the asynchronous service calls from the ViewModels, what I do is use the generated interface as the type of my service client in the viewmodel. With this I can mock the service calls in my unit tests. The services can then be injected at runtime in a different manner than at testing time. This could be another article ! Using this interfaces really helps decoupling your ViewModels from the rest of the application and especially how your service proxies are implemented. Hope this helps !
  • Ce n'est pas mieux ou pire que Selenium Entre la peste et le choléra on a toujours le choix c'est ça la démocrachie
  • @gorgoroth & @Adrian: I think there's a misunderstanding with the aim of this article. This article is not introducing a general way to test the application (Silverlight Toolkit does it already). What Nicolas highlighted is the ability to unit test Silverlight code (ViewModel that embeds Silverlight framework) and integrate those test to a CI build (without a task defined), a local environment (using Run All Tests feature) and having code metrics (code coverage, cyclomatic complexity and so on...). Silverlight Toolkit doesn't provide such features at the moment. I wouldn't compare this approach to Selenium tests but to MSTest tests. It's like comparing Selenium to JUnit :)
  • Hello Nicolas, I just tried out your simple tutorial and have got a problem when I try to add the reference: •system.dll •System.Core.dll •System.Windows.dll •System.ServiceModel.dll the project always replaces the files, with those from the .net framework. Even when I select to use a local copy, the file get replaced within the bin folder when I build the project. When I try to add System.Core VS says this library is already referenced, even when I just deleted the library. Any idea? Best regards from germany Kai G.
  • Hi Kai, Have you tried editing your unit tests .csproj file and setting the path of the libraries yourself? Hopefully, it should do the trick! Regards, Nicolas.
  • Hello Nicoals, thank you for the very fast response. Your hint worked quite good, I could add all librarys except one: System.Core When I want to add it, VS says: "System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" is incompatible with .NET Framework 4 In order to add it you should to change the project's target to a compatible framework first. You know how to solve this issue? Thank ou very much. Kai G.
  • please i am student, and i want to know more on website structure, and architecture
    1. Laisser un commentaire

      Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *


      Ce formulaire est protégé par Google Recaptcha