Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>been writing a couple of responses about unit testing and mocking lately. I wrote elsewhere that it's important to ask yourself what <em>exactly</em> are you testing. Regarding your particular situation, I would hope the answer is "I am testing the business logic my WebService is exposing", and <strong>not</strong> "I am testing my WebService" - there's a difference.</p> <hr> <p>If your concerns are <strong>server-side</strong></p> <p>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.</p> <p>You need to target your <em>business logic</em>. The best way to do this is to <em>separate</em> your business logic from your WebService. Consider the following</p> <pre><code>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 (); } } </code></pre> <p>there is no way to test that logic without invoking the WebService directly. What you really want is</p> <pre><code>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 (); } } </code></pre> <p>in prod</p> <pre><code>// 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 (); } } </code></pre> <p>in test </p> <pre><code>// test business logic without web service! yay! [Test] public void Test_DoSomething () { MyService service = new MyService (); string actual = service.DoSomething (); // verify results } </code></pre> <p>managing dependencies [like the AuthenticationService member] is a separate issue. However, making your WebMethods <strong>simple passthroughs</strong> 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.</p> <hr> <p>If your concerns are <strong>client-side</strong></p> <p>You have a business component <em>calling</em> a webservice, and I agree that you don't want to create a client for unit testing.</p> <pre><code>public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { ... public string DoSomething () { ... } } public class MyClient { public void CallService () { MyWebService client = new MyWebService (); client.DoSomething (); } } </code></pre> <p>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.</p> <pre><code>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 (); } } </code></pre> <p>in test</p> <pre><code>[Test] public void Test_CallService () { IMyWebService mockService = null; // instantiate mock with expectations MyClient client = new MyClient (mockService); client.CallService (); // verify results } </code></pre> <hr> <p>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 <em>cross a process boundary</em>, eg Database or WebService, I highly recommend applying these patterns as we did above.</p> <p>Really, it's just plain old interface development. You probably already see how it pays off.</p> <p>:)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload