Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing a WCF Client

I am working with code that currently does not use any dependency injection, and makes multiple service calls through a WCF client.

public class MyClass
{
    public void Method()
    {
        try
        {
            ServiceClient client = new ServiceClient();
            client.Operation1();
        }
        catch(Exception ex)
        {
            // Handle Exception
        }
        finally
        {
            client = null;
        }

        try
        {
            ServiceClient client = new ServiceClient();
            client.Operation2();
        }
        catch(Exception ex)
        {
            // Handle Exception
        }
        finally
        {
            client = null;
        }
    }
}

My goal is to make this code unit-testable through the use of dependency injection. My first thought was to simply pass an instance of the service client to the class constructor. Then in my unit tests, I can create a mock client for testing purposes that does not make actual requests to the web service.

public class MyClass
{
    IServiceClient client;

    public MyClass(IServiceClient client)
    {
        this.client = client;
    }

    public void Method()
    {
        try
        {
            client.Operation1();
        }
        catch(Exception ex)
        {
            // Handle Exception
        } 

        try
        {
            client.Operation2();
        }

        catch(Exception ex)
        {
            // Handle Exception
        }
    }
}

However, I realized that this changes the code in a way that affects its original behavior, based on the information from this question: Reuse a client class in WCF after it is faulted

In the original code, if the call to Operation1 fails and the client is put in a faulted state, a new instance of ServiceClient is created, and Operation2 will still be called. In the updated code, if the call to Operation1 fails, the same client is reused to call Operation2, but this call will fail if the client is in a faulted state.

Is it possible to create a new instance of the client while keeping the dependency injection pattern? I realize that reflection can be used to instantiate a class from a string, but I feel like reflection isn't the right way to go about this.

like image 621
Eric B Avatar asked Jan 20 '15 06:01

Eric B


1 Answers

You need to inject factory rather than instance itself:

public class ServiceClientFactory : IServiceClientFactory
{
    public IServiceClient CreateInstance()
    {
        return new ServiceClient();
    }
}

Then in MyClass you simply use factory to get instance each time it is required:

// Injection
public MyClass(IServiceClientFactory serviceClientFactory)
{
    this.serviceClientFactory = serviceClientFactory;
}

// Usage
try
{
    var client = serviceClientFactory.CreateInstance();
    client.Operation1();
}

Alternatively, you can inject function returning such client using Func<IServiceClient> delegate so that you can avoid creating extra class and interface:

// Injection
public MyClass(Func<IServiceClient> createServiceClient)
{
    this.createServiceClient = createServiceClient;
}

// Usage
try
{
    var client = createServiceClient();
    client.Operation1();
}

// Instance creation
var myClass = new MyClass(() => new ServiceClient());

In your case Func<IServiceClient> should be sufficient. Once instance creation logic gets more complicated it would be a time reconsider explicitly implemented factory.

like image 136
k.m Avatar answered Sep 19 '22 11:09

k.m