Silverlight 2 is the next major update of Microsoft’s Rich Internet Application (RIA) technology. It includes a cross-platform, cross-browser version of the .NET Framework, that enables a rich .NET development platform that runs in the browser . The recent release of Silverlight 2 Beta has given developers the opportunity to start developing rich internet applications using Visual Studio. So now that we can develop rich client applications in Silverlight, how can we architect a Silverlight application in a way that allows us to effectively unit test our code? The Model-View-Presenter design pattern can help to achieve this.
The MVP Pattern
The Model-View-Presenter (MVP) pattern separates user interface logic into testable components. This pattern is commonly used in ASP.NET applications to improve the testability of presentation logic. The same principals can be applied when developing applications in Silverlight 2.
There are many articles that explain the principals of the MVP pattern, so I won’t go into detail here. If you are unfamiliar with the pattern, a good introduction can be found here.
Basically, the MVP pattern consists of the following components:
Model – Represents the domain data.
View – Contains the user interface.
Presenter – Manages presentation logic and data binding.
User interface code can be difficult to test as it is usually tightly bound to controls. Separating the code from the view allows presentation logic to be more easily tested.
This separation also allows us to reuse presentation logic throughout an application. If an application contains different views of the same data, we only need one presenter to manage each view.
Unit Testing Silverlight Applications
One of the great benefits of the MVP pattern is that it allows you to unit test your presentation logic. Unfortunately, I struck some problems while attempting to unit test code written in a Silverlight project.
Visual Studio will not allow you to reference a Silverlight assembly from a standard .NET assembly. This causes a problem as unit testing frameworks, such as NUnit, are standard .NET assemblies.
The following error occurs when attempting to add a reference to NUnit in a Silverlight class library project:
“You can’t add a reference to nunit.framework.dll as it was not built against the Silverlight runtime. Silverlight projects will only work with Silverlight assemblies.”
This is understandable, as standard .NET assemblies may use framework features that are not available in the compact version of the .NET Framework in Silverlight. So, what if we add a reference to our Silverlight code to a standard .NET class library project? Well, we are then presented with this error:
“Silverlight projects can only be referenced by other Silverlight projects.”
Again, this is understandable for deployed code, as the Silverlight application may be using features specific to the Silverlight framework. But our unit test code shouldn’t contain any Silverlight-specific features.
So how can we unit test our Silverlight code if we can’t reference it from a test fixture? Well, I discovered that it is possible bypass the project reference and add a direct reference to the Silverlight DLLs from a standard class library project! This allows us to unit test the Silverlight presenter assemblies using NUnit, or any other .NET unit testing framework.
You may also find you have to reference a few Silverlight framework assemblies, such as System.dll and System.Windows.dll, but if you minimise references to Silverlight-specific features in the presenter classes, this shouldn’t be a problem.
Microsoft have announced a Unit Testing framework for Silverlight 2. There are no details on this yet, but I would be surprised if it supports third-party testing frameworks, such as NUnit and mbUnit, or mocking frameworks, such as NMock and RhinoMocks. I could be wrong though, but until then, this method seems to work just fine.
So, now that we can unit test our Silverlight code, what is the best way to architect a Silverlight application? Well, I’m sure, like any application, it depends on your project. I develop ASP.NET applications and constantly find it difficult to unit test interface logic stuck in code-behind files. This problem seems apparent in Silverlight too, as the code-behind is tightly coupled with the XAML view. We can break this coupling and split our user interface logic into separate, testable components using the MVP Pattern.
Applying the MVP Pattern to a Silverlight Application
The following describes a conceptual model for a Silverlight application implementing the MVP Pattern.
The main database, domain model and business logic reside on the server. The data and business logic is accessed by the Silverlight application through calls to Web Services. The server application can be architected independently and is not specific to the MVP Pattern.
The Silverlight client application contains only presentation logic and no business logic. Any operations that require business logic should be passed back to the server to be processed and results returned in the form of a Data Transfer Object (DTO).
The Silverlight application talks to the server via web services. Visual Studio creates a service reference that contains methods for making asynchronous calls to a web service. We can create a partial class from the generated service soap client that implements a custom interface containing methods used by the presenter. We can then call service methods through this interface rather than directly referencing the service class. Using an interface also allows us to stub-out the service when unit testing the presenter.
When the Silverlight application references a web service, a proxy data class is generated. This class acts as a Data Transfer Object (DTO) that represents a data structure for transferring data between the client and server applications. The DTO provides the model used by the view and presenter.
The view is the visual representation of the application.
The view is composed of XAML files and their corresponding code-behind files. This structure is very similar to that of an ASP.NET page.
The XAML files describe the layout and behavior of the Silverlight interface. Controls in the view are wrapped by properties in the code-behind file. Any events fired from controls are handled in the code-behind and passed up to the presenter for further processing. The presenter can also pass information back to the view through properties and methods in the code-behind.
The presenter sits between the view and the service reference. If the view requests data, the presenter will call a service reference and present the results to the view. If an action requires logic, the presenter will handle the event and process the information to send back to the view.
As an example, I have created a Silverlight application that implements the MVP pattern to display data from the Customers table in the Northwind database. The data can be edited and saved back to the database via a web service.
The solution contains the following projects:
Server Projects (Standard assemblies will reside on the server)
SilverlightMvp.DataAccess - Provides data from the Customers table using Linq to SQL.
SilverlightMvp.Web - Contains the web site that will host the Silverlight application and web services that the Silverlight application will call to access the customer data.
Client Projects (Silverlight assemblies that run inside the browser)
SilverlightMvp.View - Contains the XAML and code-behind files.
SilverlightMvp.Core – User Interface logic classes, including the presenters, service references and interfaces.
SilverlightMvp.Core.UnitTests – While not deployed to the client, this standard .NET assembly tests classes in the SilverlightMvp.Core project.
I hope this information is useful to anyone developing .NET applications in Silverlight. If you have any questions, comments or suggestions please let me know. Enjoy!