Anny Igi
Anny Igi

Reputation: 95

Fake WCF-Service calls with FakeItEasy

I want to test my Class, which calls the third Party Webservice. Is it possible to use FakeItEasy for this?

Wenn I try to Fake the Class from Reference.cs (auto generated), UnitTest started and doesn't come back.

Reference.cs(auto generated)

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class ws_AccessoryClient : System.ServiceModel.ClientBase<AccessoryService.ws_Accessory>,
        AccessoryService.ws_Accessory
    {
        public ws_AccessoryClient()
        {
        }

        public ws_AccessoryClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public AccessoryService.ResponseMessageOf_ListOf_SomeMethodInfo SomeMethod(
            AccessoryService.RequestMessageOf_SomeMethod request)
        {
            return base.Channel.SomeMethod(request);
        }
    }

Test.cs

    [Test]
    public void DoBusinessLogicTryTest()
    {
        var accessoryProxy = A.Fake<ws_AccessoryClient>();
    }

Upvotes: 1

Views: 1620

Answers (2)

tom redfern
tom redfern

Reputation: 31770

You cannot (and why would you want to?).

If you want to verify that your class under test makes the call to the service, then wrap the service call in a class who's only job it is to call the service, and define it with an interface.

interface ICallTheService
{
    void CallTheService();
}

class ServiceCaller : ICallTheService
{
    void CallTheService()
    {
        // Call the service...
    }
}

Then you can fake this class and verify that your class under test invokes the CallTheService operation.

// fake the service caller and pass it into your service
var serviceCaller = A.Fake<ICallTheService>();

// Verify invocation
A.CallTo(() => serviceCaller.CallTheService()).MustHaveHappened();

I want to test the logic in my class, depends on Response from WCF-Service

This is where I think you're going wrong with separation of concerns. Your test is called DoBusinessLogicTryTest, yet it has a dependency on System.ServiceModel, which is an infrastructure concern. Your business logic should be testable without this dependency. If your class under test needs to behave differently depending on the response, you could do something like this:

interface ICallTheService
{
    ServiceResponseModel CallTheService();
}

enum ServiceResponseModel
{
    Success,
    PartialSuccess,
    FailureCondition1,
    FailureCondition2,
    // etc...
}

Then you can prime the ICallTheService fake to return each of the possible responses and test your class based on this.

A.CallTo(() => serviceCaller.CallTheService()).Returns(ServiceResponseModel.Success);

For Example if some Exceptions (defined in WCF) are handled correct

This is also nothing to do with business logic. The actual handling of exceptions is the responsibility of the ICallTheService implementation. In fact, I would introduce another class for this, whose job it would be to translate the various possible exceptions from System.ServiceModel into your response model. Eg

class WCFErrorResponseTranslator
{
    ServiceResponseModel TranslateWCFException (Exception ex)
    {
        if (ex.GetType() == typeOf(TimeoutException)) { return ServiceResponseModel.TimeOut; }
        /// etc
    }
}

This behaviour could then be tested in isolation.

Upvotes: 2

Bronumski
Bronumski

Reputation: 14272

As has been mentioned you may not want to do what you are purposing for Unit Testing as this would cause more noise than is necessary for a Unit Test which could used mocked interfaces. However it is a valid approach for integration testing, this would allow you to test that your WCF wiring is working as you expect it. It also allows you to test your application as whole if you are adopting a more behaviour driven style of testing where you want to mock as little as possible.

I use this approach myself for spinning up fake endpoints using NSubstitute which is covered in my blog Hosting a Mock as a WCF service. The main things you need to do is spin up a ServiceHost, give it the endpoint address you want to use, set the context mode to single and provide the mock you want to use as the endpoint.

var serviceHost = new ServiceHost(mock, new[] { baseAddress });

serviceHost.Description.Behaviors
    .Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
serviceHost.Description.Behaviors
    .Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;

serviceHost.AddServiceEndpoint(typeof(TMock), new BasicHttpBinding(), endpointAddress);

One thing that I do in my testing is randomly choose the port that I host the endpoint on and inject the address into my application during testing. That way your tests will be able to run on other machines and build servers without clashing with other ports in use.

After looking at your example you might want to consider using the WCF ChannelFactory to create your client instead of using a concrete proxy client class. The ChannelFactory creates a proxy on the fly using the Interface you provide and allowing you to inject the proxy into its dependencies using the service interface. This would make unit testing easier and give you a more decoupled design.

Upvotes: 3

Related Questions