2

TL;DR: What is a good and testable way to implement the dependency between the ViewModels and the WCF services in a MVVM client?

Please read the rest of the question for more details about the problems I encountered while trying to do this:


I am working on a silverlight client that connects to a wcf service, and I want to write unit tests for the client. So I'm looking for a good solution for using the wcf clients in my ViewModels and testing that interaction. I have found two solutions until now:

Solution 1: This is actually how I have implemented it until now:

public class ViewModelExample
{
    public ViewModelExample(IServiceClient client)
    {    
            client.DoWorkCompleted += .. 
            client.DoWorkAsync();
    }
}

//This is how the interface looks like
public interface IServiceClient
{
    event EventHandler<AsyncCompletedEventArgs> DoWorkCompleted;
    void DoWorkAsync();
}

//I was able to put the interface on the generated clients because they are partial classes, like this:
public partial class GeneratedServiceClient : IServiceClient
{

}

The good part: it's relatively easy to mock

The bad part: my service client lives as long as my ViewModel, and when I have concurrent requests I don't know which answer belongs to which request.

Solution 2: Inspired by this answer WCF Service Client Lifetime.

public class ViewModelExample
{
    public ViewModelExample(IServiceFactory factory)
    {
        var client = factory.CreateClient();
        client.DoWorkCompleted += ...
        client.DoWorkAsync();
    }
}

The good part: each request is on a different client, so no more problems with matching requests with answers.

The bad part: it's more difficult to test. I would have to write mocks for both the factory and the wcf client every time. This is not something I would like to do, since I alreay have 200 tests... :(

So my question is, how do you guys do it? How do your ViewModels talk to the wcf services, where do you inject the dependency, and how do you test that interaction? I feel that I'm missing something..

Community
  • 1
  • 1
stralsi
  • 988
  • 1
  • 10
  • 17

3 Answers3

1

Try having a Func<IServiceClient> injected into your VM instead of the a client instance; you'll have a 'language-level factory' injected instead of building a class for this. In the factory method you can instantiate your client however you want (each access could create a new instance for that for example).

The downside is that you'll still have to touch your tests for the most part, but I assume it will be less work:

public ViewModelExample(Func<IServiceClient> factoryMethod)
{
    var client = factoryMethod();
    client.DoWorkCompleted += ...
    client.DoWorkAsync();
}
Stefan Szasz
  • 1,247
  • 11
  • 27
0

The WCF service should have it's own tests that confirm the functionality of itself.

You should then be mocking this WCF service and writing unit tests within your consumers.

Unfortunately, it's a pain and something we all have to do. Be pragmatic and get it done, it will save you getting bitten in the future.

ChrisBint
  • 12,773
  • 6
  • 40
  • 62
  • 1
    thanks Chris, but that is exactly what I was asking, how to write the services and how to write mocks for them? How do you do it? – stralsi Jun 20 '12 at 19:47
0

Are you using IoC container by a chance? If you had, this problem would be totally mitigated by container (you'll simply register IService dependency to be created as brand new upon each request).

If that's not the case, then

I would have to write mocks for both the factory and the wcf client every time

is how you deal with this kind of "problems". The cost is relatively small, probably 2-3 extra lines of code per test (all you have to do is setup factory mock to return service mock, which you do need either way).

k.m
  • 30,794
  • 10
  • 62
  • 86
  • Currently I'm not using an IoC container, but in my opinion that would not change the situation since the IService dependency is in the constructor, and I would need one per call. .. but you gave me another idea, would you think it is feasible to use the IoC container instead of the factory? To resolve the IService before each call? – stralsi Jun 20 '12 at 13:16
  • @sssilviu: what makes you think you wouldn't be able to provide client instance per VM? Most modern containers allow you to greatly control objects instantiation/lifetime. Whenever new VM instance is created (assuming it is created via container), it can be fed with new instance of `IService`, thus making IoC container work *exactly* like the factory/function factory. This is just a matter of configuration/registrations. – k.m Jun 20 '12 at 14:29
  • I currently have client instances per VM. I need them per service call. – stralsi Jun 20 '12 at 14:49
  • The problem with client instances per VM is when the VM makes 10 requests on the same method, from the same client, when the answers return I do not know which answer belongs to which request. – stralsi Jun 20 '12 at 14:51
  • 1
    @sssilviu: I see. Then you should use factory to get new client instance from same VM. Note that some containers (for one, [Autofac](http://code.google.com/p/autofac/) lets you do that), will resolve dependencies to `Func` even if you simply register `IService`. The `Func` wrapping is done automatically by container. – k.m Jun 20 '12 at 15:30