ViewModel + .NET RIA Services Part 2: Testability, Server Mocking and Dependencies

A demonstration of testability of view models, mocking the server when using .NET RIA Servces, in conjunction with dependency injection and the IoC implementation from Silverlight.FX to help facilitate the overall implementation.

In Part 1 of ViewModel and .NET RIA Services, which I recommend you check out first if you haven't, I created a simple product search UI using Silverlight and .NET RIA Services using the ViewModel (aka MVVM) pattern. One of benefits of the ViewModel pattern is that it creates a nice contract between the view and associated logic, i.e. a contract between the designer and the developer. Another key benefit of the ViewModel pattern is that it furthers testability - more of your presentation tier is now unit testable. This post touches on that second benefit.

In doing so, it will allow me to go into a couple of other related topics:

  • First, this application uses .NET RIA Services. This post will demonstrate how you can mock out the server when using the client-side functionality of .NET RIA Services. This is important because it allows the view models to be tested independently outside of the end-to-end application, thereby minimizing dependencies.
  • Second, once we factor out dependencies from within the view model, we need something like dependency injection to initialize view models. This post will also demonstrate the super-minimal and lightweight IoC container and dependency injection implementation in Silverlight.FX
  • .

Mocking the Server

On the server, I have defined a Catalog domain service using .NET RIA Services, which makes a Catalog object along with a list of Products available for my client side code, and specifically, the view model implementation to use. Here is a brief snippet of that view model code from last time:

public class SearchViewModel : Model {
    private Catalog _catalog;

    public SearchViewModel() {
        _catalog = new Catalog();
    }

    public IEnumerable<Product> Products {
        get {
            return _catalog.Products;
        }
    }

    public void Search(string keyword) {
        ...
        _catalog.Products.Clear();
        _catalog.LoadProducts(keyword);
    }
}

As you can see, the view model simply instantiates a Catalog instance and starts using it. It doesn't have to worry about how the client-side Catalog object communicates with its server-side Catalog counterpart, URIs etc., thanks to the infrastructure provided by .NET RIA Services.

However, the architecture of the client-side bits does include a layering, where the client-side programming model (i.e. the Catalog, its list of Products, Load etc.) are layered on a proxy layer that encapsulates serialization and transport. The default proxy layer uses DataContract serialization and HTTP to communicate with the implicit service endpoints created on the server. If you look at the generated code you'll see the following:

public class Catalog : DomainContext {

    public Catalog() : base(new HttpDomainClient(new Uri("..."))) {
    }
}

Here is a diagram that shows the different pieces and how they are related:

DomainContext, and DomainClient

The DomainClient interface is a generic proxy interface. It represents the ability to issue a query, process a change set, or invoke an operation. You can implement your own version of a DomainClient, and use that instead of the HTTP domain client. For example, you could write a DomainClient that knew how to speak to Twitter, and thereby expose the .NET RIA Services programming model over the Twitter API (idea for followup post). More specifically, in the context of this post, I can create a DomainClient that surfaces some local mock data and use that when constructing a mock Catalog that I use within my view model at unit test time.

The code associated with the blog post has a derived implementation called LocalDomainClient that simplifies writing such a mock when everything is local and asynchronous operation is not necessary. Specifically it implements all the async methods on DomainClient (Begin/EndQuery, Begin/EndSubmit, and Begin/EndInvoke ) and turns around and calls into synchronous methods that you get to override in your mock (Query, Submit and Invoke).

Here's the implementation of my mock DomainClient from within the Test project:

public class MockDomainClient : LocalDomainClient {

    private IEnumerable<Entity> _mockEntities;

    public MockDomainClient(IEnumerable<Entity> mockEntities) {
        _mockEntities = mockEntities;
    }

    protected override IQueryable<Entity> Query(string queryName, IDictionary<string, object> parameters) {
        // This can be as complex as you want it to be; alternatively you can create specific
        // mocks for each unit test you have, thereby simplifying the implementation of Query.
        return _mockEntities.AsQueryable();
    }
}

When I want to use this mock, I simply need to use the overload of the Catalog constructor that takes in a DomainClient. For example:

DomainClient mockDomainClient = new MockDomainClient(...);
Catalog mockCatalog = new Catalog(mockDomainClient);

The APIs on this mock Catalog instance work just like a real Catalog, which is key. Essentially you can replace the underlying serialization and transport layer without changing the programming model that layers on top.

Factoring the ViewModel to use a Mock

Now that I have the ability to create and use a mock Catalog, I need my view model to do so at unit test time, while using the real Catalog at runtime. Recall from above, that currently my view model constructs an instance of Catalog in its constructor. Instead, I'd like it to take a Catalog instance in its constructor.

public class SearchViewModel : Model {
    private Catalog _catalog;

    public SearchViewModel(Catalog catalog) {
        _catalog = catalog;
    }
}

With this change, I can write the following unit test, using the Silverlight unit testing framework:

[TestClass]
public class SearchViewModelTests : SilverlightTest {

    [TestMethod]
    [Asynchronous]
    public void TestEmptyKeywordIsIgnored() {
        bool searchStarted = false;

        // The setup...
        List<Entity> mockEntities = new List<Entity>();
        Catalog catalog = new Catalog(new MockDomainClient(mockEntities));

        SearchViewModel viewModel = new SearchViewModel(catalog);
        viewModel.SearchStarting += delegate(object o, EventArgs e) {
            searchStarted = true;
        };

        // The test...
        viewModel.Search(String.Empty);

        EnqueueDelay(1000);

        // The verification
        EnqueueCallback(() => Assert.IsFalse(searchStarted, "Did not expect a search to start."));
        EnqueueTestComplete();
    }
}

Test Run ScreenshotNote that as you'd expect by now, the view model is passed in a mock Catalog, and hence I have no dependencies on any of my server code. In fact, I don't have any dependencies on a server either. So I can run the unit tests without deploying into a Web application. Simply load up the test HTML page created for a Silverlight application into the browser.

In similar fashion, I can write some more tests to test more of the behavior of my SearchViewModel, which you'll see when you open up the project and code associated with the blog post. Here is a screenshot of running the tests:

Dependencies and IoC

So at this point, we have our view model taking in a Catalog, the unit tests mocking the server using a mock DomainClient, and passing in a mock Catalog into the view model.

However, now at runtime we need to pass in a real Catalog using the default HttpDomainClient that does go back to the server to implement Query, Submit and Invoke. There are multiple ways to do this. One simple approach is to have the view model continue to instantiate a Catalog when one is not passed in. An alternative is to express this as a dependency and have an external IoC container satisfy this dependency. Depending on your tastes, and needs, this might be interesting, and I'll use this post as a context to introduce the IoC container and functionality provided by Silverlight.FX.

First, I'll declare Catalog as a dependency.

public class SearchViewModel : Model {
    private Catalog _catalog;

    public SearchViewModel([Dependency] Catalog catalog) {
        _catalog = catalog;
    }
}

As simple as that. Either constructor parameters or get/set properties can be marked as dependencies. Dependencies can be required (the default), or marked as optional.

Next, I'll go and initialize my container. By default, in Silverlight.FX, the Application is a global container. You can create your own containers at logical scopes, but for this, the global container will suffice. Furthermore, Application provides a XAML-friendly way to define a set of components to populate this global container. So, in XAML, I can define the following:

<fxapp:XApplication
    xmlns:fxapp="clr-namespace:SilverlightFX.Applications;assembly=SilverlightFX"
    ...>
  <fxapp:XApplication.Components>
    <fxapp:ComponentFactory ComponentType="MyApp.DomainLogic.Catalog" />
  </fxapp:XApplication.Components>
</fxapp:XApplication>

In this example, I want a new instance of Catalog to be created each time a dependency of type Catalog is to be fulfilled. Hence I am using . If I wanted a common Catalog instance to be shared, I could use the following XAML just as well:

<fxapp:XApplication.Components>
    <app:Catalog />
</fxapp:XApplication.Components>

That's all I have to do. When the view model is created by the view, the framework code in Silverlight.FX, checks if there is an IoC container available, and there is one, since we've defined some components, it delegates creation of the view model to the container. The container attempts to create and initialize any object by fulfilling the dependencies of those objects by satisfying dependencies of that object.

Summary

So there you have it... to recap, one of the important benefit of using the view model pattern is increased testability. You can use .NET RIA Services and mock the server using the DomainClient extensibility point while testing your client-side view models. If you're using the view model pattern implementation as it exists in Silverlight.FX, you can also use the complementary lightweight IoC and dependency injection system.

Here is the code for the entire project, along with unit tests.

I did not touch on testability and unit testing the code in the Catalog domain service that runs on the server. That is certainly possible, and will visit that in the future. This post is scoped to the view model pattern and client-side half of the overall picture.

Posted on Wednesday, 5/13/2009 @ 2:40 PM | #Silverlight


Comments

37 comments have been posted.

MichaelD!

Posted on 5/13/2009 @ 6:27 PM
This is great stuff Nikhil. I'm glad to see there's some support for client-side IoC. Do you know if there's any support on the server-side for IoC? That is, how do you configure your DomainServices to be instantiated through specified a IoC container? Easy to do in WCF. Tricky to find something for RIA. :)

MichaelD!

Posted on 5/13/2009 @ 7:43 PM
I answered my own question here: http://silverlight.net/forums/p/95860/219611.aspx

jsp3536

Posted on 5/13/2009 @ 8:29 PM
How did you get SearchView.Model.cs to appear as a node under the SearchView.xaml node in the solution explorer of visual studios?

Troy

Posted on 5/13/2009 @ 9:03 PM
The sample gives me this any idea why?

Error 1 'System.Windows.Ria.Data.QueryCompletedResults' does not contain a constructor that takes '2' arguments

Troy

Posted on 5/13/2009 @ 9:18 PM
The sample gives me this any idea why?

Error 1 'System.Windows.Ria.Data.QueryCompletedResults' does not contain a constructor that takes '2' arguments

Nikhil Kothari

Posted on 5/14/2009 @ 12:53 AM
@Troy - you're probably hitting a change in the May CTP from the March CTP of RIA Services (which is what this sample uses). Don't know off the top of my head on what it would be, but I suspect it is something reasonably straightforward to change in the sample.

@jsp3536 - if you check out the .csproj, you'll see that SearchView.Model.cs has a <DependentOn> node - while conceptually its opposite (the view depends on the model, and not vice versa), the end result in the solution explorer is what you want. Unfortunately there is no way to add that dependency in the IDE. This is something I wish we get out-of-the-box as the tools (incl. project system) understand the view model pattern. Until then its manual. I do it because it cleans up the solution explorer experience.

James

Posted on 5/14/2009 @ 1:48 AM
Is there an easy way to test the domain service if it uses EF?

Mike Lockyer

Posted on 5/14/2009 @ 5:24 AM
Very good example ...

I have been working on something similar but having a problem finding a way to bind to SelectedItems with the ViewModel

I need this as my app allows multiple selection of items in a DataGrid

SelectedItems is available within the code behind but I cannot bind it to the ViewModel

Any advice

Thanks

Mike

Nikhil Kothari

Posted on 5/14/2009 @ 7:55 AM
@James - probably the best thing to think about is using the repository pattern for that scenario. I don't know if EF will provide better mockability in the next version. If it did, that would be useful here.

@Mike - when something isn't bindable, then you've got two options:
a) Pass the list of selected items to the view model when invoking some operation.
b) Handle selection change events and in response pass the selected items to the view model either using triggers and actions or code-behind. I personally think code-behind is a fine thing to use to implement the glue between view and view model when declarative constructs don't work. As long as the code-behind doesn't contain more than view-specific logic, it is fine.

Robert Kozak

Posted on 5/14/2009 @ 12:44 PM
I found out that the Hover effect is giving a AmbigiousMatchException... When will you have a build of Silverlight.FX for Silverlight 3?

Robert Kozak

Posted on 5/14/2009 @ 1:45 PM
Nikhil,

This project has not been updated for the RIA Services May refresh has it? The QueryCompletedResults now has an extra param QueryCompletedResults(IEnumerable<Entity> entities, int resultCount, int totalCount);

Nikhil Kothari

Posted on 5/15/2009 @ 6:36 AM
@Robert
Silverlight.FX already works for SL3. I haven't seen an issue with HoverEffect, but will try again. In any case, I am going to start working on this as the next thing I am working on will be on SL3 as well.

And you're right, this was built on the March CTP of RIA Services... I wrote this up before the May CTP was published, but blog post didn't go up before. For the specific sample, its probably fine to to pass the count of the list of mock entities to both counts. I need to go and see why we made a change to have two counts here. :-)

Robert Kozak

Posted on 5/15/2009 @ 1:49 PM
Nikhil. I have been including the complete source of SilverLight.FX in my solution and recompiling in case I decide to fork it and add my own changes. The example in this blog post has a different version of Silverlight.FX that at the very least has a new type called ComponentFactory. I dont have this. When will you be updating the source code on http://projects.nikhilk.net/SilverlightFX/ ??

Nikhil Kothari

Posted on 5/16/2009 @ 6:58 PM
@Robert -
Updated now. Also, you can always follow this on GitHub to stay up-to-date etc.

Pierre

Posted on 5/20/2009 @ 1:01 PM
Great !
But I experience a strange behavior (outside topic of .NET RIA...but with your IoC framework):

A is declared as an implementation of service IA
B is declared as an implementation of service IB

A and B are added as singleton in Components section of MyApp.xaml
MyAppWindowModel declares a dependency on IA (as property)
AModel declares a dependency on IB (as property)

IA dependency is resolved correctly
IB dependency is never resolved (property remains null)

Does your framework support dependency between services ? (A kind of recursivity...)

A scheme to summarize - perhaps even less clear than my explanation :) -
App (with components A & B) -> Window -> WindowModel depends on service A -> AModel depends on service B)

mambo

Posted on 5/21/2009 @ 7:32 AM
Nice post! And i'm expecting for the back/forward browser integration of silverlightFX.

Pierre

Posted on 5/25/2009 @ 2:41 AM
More information about my first comment:

In fact issue is not with dependency resolution, it is with ModelType xaml tag.

1) In Window.xaml, ModelType tag works well.

2) In A.xaml, ModelType tag throws a xaml parse exception. A is a ViewUserControl. (here is the problem that I do not understand)

3) So, in my first attempt, I have replaced ModelType by defining a Datacontext (AModel).
And, in this case, dependency is not resolved.

4) My current solution:
Remove Datacontext.
Manually setting base.ModelType = typeof(AModel) in A.xaml.cs works well and dependency is resolved.

So, why ModelType declarative way only works in my MainWindow and not in my ViewUserControl ?

Nikhil Kothari

Posted on 5/25/2009 @ 6:39 AM
@Pierre - its likely that the string type name you're using for ModelType cannot be resolved into an actual type. Silverlight XAML doesn't have {x:Type}, or even full parsing context to resolve types correctly, and hence the TypeConverter tries to do the best possible job:
Simple type name -> Type in same assembly/namespace as current Application
Namespace qualified type name -> Type in same assembly as current Application
Assembly qualified type name -> lookup the type

I suspect you're trying a simple type name, but the type is in a different namespace. Can your try namespace-qualified type name?

Pierre

Posted on 5/25/2009 @ 1:46 PM
Thanks a lot Nikhil.
You saved me a headhache :p

You are right.
In fact in my case, I must use third option (Assembly qualified type name):

ModelType="MyCompany.Silverlight.SubName.AModel, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

Nikhil Kothari

Posted on 5/25/2009 @ 3:23 PM
@Pierre - I know the assembly qualified type name blows... its unfortunate to not have true type support. You might want to try partial assembly name, i.e. without the version, culture and public key and see if that works.

Pierre

Posted on 5/26/2009 @ 7:27 AM
It was my first try... but not enough.

I think that the main problem is that thrown exception gives almost no hint.

Whatever, thank you for the "tip".

hvac

Posted on 8/6/2009 @ 8:11 AM
Thanks a lot, you saved me a lot of my precious programming time :)

Manoj Sharma

Posted on 8/18/2009 @ 3:24 AM
Hello All,

Can anyone help me from where i can download the sample code used for this post?
Sorry for such a basic question but i am beginner in this direction and really need help.

Thanks in advance.

Harvey Waters

Posted on 9/17/2009 @ 3:14 AM
Is there anyway I can use IOC to mock the viewmodel itself in SilverlightFX. I want to isoloate the View so Ican test its bindings and code-behind file.

Thanks

John Mathis

Posted on 10/7/2009 @ 10:18 AM
Thanks for the article. Using LocalDomainClient seems like a good approach. I'm having difficulty with one thing and wondered if you might have some idea of what's going on. I have a VERY simple entity - User - and a very simple repository. All works just fine running the application. This gets correct results in my viewmodel:
private void loadOp_Completed(object sender, EventArgs e)
{
Users = ((LoadOperation<User>)sender).Entities.ToList();
}

However, when called from my test using a MockDomainClient with mock data (a list containing 1 user), the line above results in an empty list. Further, this line from LocalDomainClient.BeginQueryCore properly results in localQuery containing my test user:
IQueryable<Entity> localQuery = Query(queryName, parameters);

Any idea where the things might be going wrong?

Thanks,

John

Phil Steel

Posted on 12/7/2009 @ 4:48 AM
Hi Nikhil

Can't see the code download - an empty rectangular box with a redline at the bottom is displayed instead (on FF and IE6).

Phil

Abacate

Posted on 2/25/2010 @ 11:16 AM
I am not able to locate the class LocalDomainClient, can someone help me find where is those implementation\assembly?

where is those class??

Abacate

Posted on 2/25/2010 @ 11:22 AM
I found It, sorry to be stupid like that

Rodrigo Rodriguez

Posted on 2/25/2010 @ 5:26 PM
Nice work. Thanks.
We are trying not to use MockDomainClient, instead, we are currently use RhinoMocks. It has worked:

[TestMethod]
[Asynchronous]
public void ViewShouldReturnCorrectDisplayName()
{
var Order = new Order { Id = 1, CategoriaId = 1, ClienteId = 2};
var Orders = new List<Entity> {Order};

var domainClient = _mocks.DynamicMock<LocalDomainClient>();
Expect.Call(domainClient.SupportsCancellation).Return(false);
Expect.Call(domainClient.Query("GetOrders", null)).Return(Orders.AsQueryable());
domainClient.Replay();

var viewModel = new FindOrdersViewModel(null, null, domainClient);
viewModel.SearchAll();

EnqueueDelay(1000);

Assert.IsTrue(viewModel.Orders.Count == 1);
}

john mcfetridge

Posted on 3/12/2010 @ 8:35 AM
was wondering if u are going to update localDomainClient for SL 4 and WCF RIA?

Mircea Pleteriu

Posted on 3/24/2010 @ 8:54 AM
Do you have an updated LocalDomainClient for SL 4 and WCF RIA 4 RC?

Eric Quist

Posted on 3/29/2010 @ 6:47 AM
It would be great with an updated example for SL 4 and WCF RIA 4 RC.

chris

Posted on 5/15/2010 @ 4:15 AM
Hello Nikhil

Do you plan to provide an updated version for silverlight 4 and RIA 4 ?

Thanks

Anton Swanevelder

Posted on 9/1/2010 @ 1:18 AM
I found this post on the silverlight forums where the person updated the LocalDomainClient to Silverlight 4. This may help to cross the bridge to SL 4. http://forums.silverlight.net/forums/p/198164/463823.aspx#463823

Kaveh

Posted on 8/22/2011 @ 11:29 PM
Really liked it and implemented it in my app, but seems TFS build server doesn't like it. Any unit test that use the TestDomainClient raises this exception:
System.DllNotFoundException: Unable to load DLL 'agcore': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

James Manning

Posted on 8/24/2011 @ 5:59 AM
@Kaveh - agcore is (as you'd imagine) part of the core Silverlight framework. Make sure you're running with .NET 4 as the target framework for your tests (.NET 4 can load silverlight assemblies AFAIK) and that silverlight is installed on your build server (or check in the silverlight assemblies and have them referenced from there).

I'm not sure if there are any methods currently available for doing automated unit tests that run in the actual Silverlight runtime - there is/was the framework that would run tests for you via a browser app, but it didn't seem useful as part of an automated CI/nightly build. I'd love to find out if there are better/easier options than just getting the necessary Silverlight bits available for .NET 4 unit tests. :)

Corporate Relocation

Posted on 10/22/2011 @ 4:38 AM
Movers Packers provides - Packers and Movers, movers and packers, Packing Moving, Loading Uploading services, Car Transportation service providers in delhi, mumbai, gurgaon, hyderabad, chennai, and All over india and overseas.
Post your comment and continue the discussion.