Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a web service

Do I have to rewrite my code to do this into an interface? Or is there an easier way? I am using Moq

like image 314
zachary Avatar asked Oct 23 '09 18:10

zachary


People also ask

What do you understand by mocking web service?

In general, mocking is creating a virtual service that works like a real service. A mock service imitates a real REST or SOAP API – it contains definitions for operations that clients call, receives requests, and returns simulated responses.


2 Answers

What I usually do is build a wrapper or an adapter around my web service and just mock that.

for instance:

public class ServiceAdapter: IServiceAdapter {     public void CallSomeWebMethod()     {         var someService = new MyWebService();         someService.SomeWebMethod();     } } 

Then I just stub the service adapter.

[Test]     public void SomeMethod_Scenario_ExpectedResult() {     var adapterMock = new Mock<IServiceAdapter>();     //do your test } 
like image 127
Joseph Avatar answered Sep 20 '22 05:09

Joseph


been writing a couple of responses about unit testing and mocking lately. I wrote elsewhere that it's important to ask yourself what exactly are you testing. Regarding your particular situation, I would hope the answer is "I am testing the business logic my WebService is exposing", and not "I am testing my WebService" - there's a difference.


If your concerns are server-side

You do not need to test WebServices in general. MS has already done that. Millions of people have done that. Testing the transport layer, the protocol, the definition of WebServices is a waste of time.

You need to target your business logic. The best way to do this is to separate your business logic from your WebService. Consider the following

public class MyWebSevice : System.Web.Services.WebService {     private AuthenticationService _auth = new AuthenticationService ();     private int _count = 0;     [WebMethod]     public string DoSomething ()     {         // embedded business logic, bad bad bad         if (_auth.Authenticate ())         {             _count++;         }         return count.ToString ();     } } 

there is no way to test that logic without invoking the WebService directly. What you really want is

public class MyService  {     // keeners will realise this too should be injected     // as a dependency, but just cut and pasted to demonstrate     // isolation     private AuthenticationService _auth = new AuthenticationService ();     private int _count = 0;     public string DoSomething ()     {         if (_auth.Authenticate ())         {             _count++;         }         return count.ToString ();     } } 

in prod

// this web service is now a consumer of a business class, // no embedded logic, so does not require direct testing public class MyWebSevice : System.Web.Services.WebService {     private readonly MyService _service = new MyService ();      [WebMethod]     public string DoSomething ()     {         _service.DoSomething ();     } } 

in test

// test business logic without web service! yay! [Test] public void Test_DoSomething () {     MyService service = new MyService ();     string actual = service.DoSomething ();     // verify results } 

managing dependencies [like the AuthenticationService member] is a separate issue. However, making your WebMethods simple passthroughs to proper underlying business classes and removing logic from them completely, allows you to target "real" user code as opposed to the plumbing of your typical WebService implementation.


If your concerns are client-side

You have a business component calling a webservice, and I agree that you don't want to create a client for unit testing.

public partial class MyWebService :     System.Web.Services.Protocols.SoapHttpClientProtocol  {     ...     public string DoSomething () { ... } }  public class MyClient {     public void CallService ()     {         MyWebService client = new MyWebService ();         client.DoSomething ();     } } 

Here, you have dependency issues, namely you cannot test MyClient.CallService without instantiating and hosting your WebService. Especially disconcerting if you do not own or host said remote service. In this case, yes, you should write against an interface - once again to separate and isolate business logic.

public interface IMyWebService {     string DoSomething (); }  public class MyWebServiceWrapper : IMyWebService {     public string DoSomething ()      {         MyWebService client = new MyWebService ();         client.DoSomething ();     } }  public class MyClient {     private readonly IMyWebService _client = null;     public MyClient () : this (new MyWebServiceWrapper ()) { }     public MyClient (IMyWebService client)     {         _client = client;     }     public void CallService ()     {         _client.DoSomething ();     } } 

in test

[Test] public void Test_CallService () {     IMyWebService mockService = null;     // instantiate mock with expectations     MyClient client = new MyClient (mockService);     client.CallService ();     // verify results } 

In general, if a class's dependencies are in-proc services, the decision to apply a pattern like Dependency Injection [DI] or Inversion of Control [IoC] is up to you - and your desire to isolate and unit test these services will inform your design. However, if a class's dependencies cross a process boundary, eg Database or WebService, I highly recommend applying these patterns as we did above.

Really, it's just plain old interface development. You probably already see how it pays off.

:)

like image 39
johnny g Avatar answered Sep 22 '22 05:09

johnny g