Mocking Web Service Proxies using the Adapter Pattern to Allow Unit Testing

Introduction

Web services are a part of many applications today. Typically, client applications access web services through proxy classes, which are either generated by a tool or written by hand. Your client application communicates to those web services through those proxy classes.

However, many applications that communicate with web services end up tightly coupling themselves to those web services, which makes the application’s code very difficult to unit test. This article proposes a technique that can be used to avoid that tight coupling and make writing your unit tests correctly easy to accomplish.

All the code in this article is supposed to be C#. It has been written by hand, but I believe the code should be accurate enough for the reader to gain an understanding of what the code is supposed to do.

This post was inspired by a question on stackoverflow.com.

Scenario

You’re developing a client application which uses a single third party web service to authenticate users and track statistics on your application’s usage. You’ve already generated a proxy class that you can use to communicate with that web service using a tool.

Your code looks a little like this:

  1. class UserServiceProxy
  2. {
  3.     // Auto-generated proxy class.
  4.     public Boolean Authenticate(String user, String password);
  5. }
  6.  
  7. class UserManager
  8. {
  9.     public String CurrentUser
  10.     {
  11.         get; private set;
  12.     }
  13.  
  14.     public Boolean Login(String user String password)
  15.     {
  16.         var proxy = new UserServiceProxy();
  17.  
  18.         if (proxy.Authenticate(user, password))
  19.         {
  20.             CurrentUser = user;
  21.             return true;
  22.         }
  23.         else
  24.         {
  25.             CurrentUser = null;
  26.             return false;
  27.         }
  28.     }
  29. }

Fair enough – it looks like if the service says the user’s authenticated, we store the user’s name. If not, we reset the user’s name. Let’s confirm that with some unit tests…

Hang on a minute. If you run a unit test on that code, it’s going to call into the third party web service. If we use a valid user’s credentials, we’ll end up screwing with the statistics that the service is recording.

However, we can just create special test users and log in with those credentials, right? Well, not if you want deterministic unit tests. What if the web service goes down, or screws up a response? Random test failures are a major (and I say this from experience) pain in the ass.

Where do we go from here?

Mocking

We need to mock the web service. We’ll create a class that pretends to be the proxy to the web service, and we can then control the responses that class sends back to our UserManager instance. Because we control exactly what gets sent back from this ‘mock proxy’ we can simulate authentication success, failure, and even exceptions.

But hang on, our design doesn’t yet support mocking:

  • There is no way to change the object that provides authentication in the UserManager class.
  • The proxy is not coded to implement an interface.

The first point is the most important. We’ve tightly coupled UserManager with UserServiceProxy. We can however, make the following improvement.

  1. class UserManager
  2. {
  3.     // Other code omitted for clarity.
  4.  
  5.     private readonly UserServiceProxy proxy;
  6.  
  7.     public UserManager(UserServiceProxy proxy)
  8.     {
  9.         if (proxy == null)
  10.         {
  11.             throw new ArgumentNullException("proxy");
  12.         }
  13.  
  14.         this.proxy = proxy;
  15.     }
  16.  
  17.     public Boolean Login(String user, String password)
  18.     {
  19.         if (proxy.Authenticate(user, password))
  20.         {
  21.             CurrentUser = user;
  22.             return true;
  23.         }
  24.         else
  25.         {
  26.             CurrentUser = null;
  27.             return false;
  28.         }
  29.     }
  30. }

Now we supply the proxy we want to use for authentication in the UserManager class’s constructor.

The second point, that the proxy class isn’t coded to an interface may be slightly less important depending upon your circumstances. If all the methods you want to mock are virtual, then fine – you can derive from the proxy class and override those methods. However, even then you still may have issues. Our mock object doesn’t need anything that’s in UserServiceProxy, and to be honest, we’ve not really got a clue what UserServiceProxy does on construction – it could be contacting the web service to do some initialization for all we know.

It would be much cleaner if we could write our mock class to an interface. However, UserServiceProxy doesn’t implement an interface…

The Adapter Pattern

We can’t touch UserServiceProxy’s code – it’s generated by a tool. But we can use the adapter pattern to create a class which enables UserServiceProxy to conform to an interface. We can then pass an instance of that interface into UserManager’s constructor.

Let’s start with the interface:

  1. interface IUserAuthenticationProvider
  2. {
  3.     Boolean Authenticate(String user, String password);
  4. }

Now, we need a class which implements that interface, but uses ClientServiceProxy for its implementation:

  1. class ClientServiceProxyAdapter :
  2.     ClientServiceProxy, IUserAuthenticationProvider
  3. {
  4.     #region IUserAuthenticationProvider Implementation
  5.  
  6.     public IUserAuthenticationProvider.Authenticate(String user, String password)
  7.     {
  8.         return base.Authenticate(user, password);
  9.     }
  10.  
  11.     #endregion
  12. }

Now we update our UserManager class to accept instances of IUserAuthenticationProvider:

  1. class UserManager
  2. {
  3.     // Other code omitted for clarity.
  4.  
  5.     private readonly IUserAuthenticationProvider proxy;
  6.  
  7.     public UserManager(IUserAuthenticationProvider proxy)
  8.     {
  9.         // Constructor code same as previous example.
  10.     }
  11. }

Cool. Now when we create our UserManager, we create an instance of ClientServiceProxyAdapter and pass it in to UserManager’s constructor. If we’re unit testing, we’ll pass in an instance of a mock class that implements IUserAuthenticationProvider. Lets create out mock class now:

  1. class MockUserAuthenticationProvider : IUserAuthenticationProvider
  2. {
  3.     Func<String, String, Boolean> AuthenticateImpl { get; set; }
  4.  
  5.     public Boolean IUserAuthenticationProvider.Authenticate(
  6.         String user, String password)
  7.     {
  8.         if (AuthenticateImpl == null)
  9.         {
  10.             throw new InvalidOperationException(
  11.                 "Cannot call Authenticate when AuthenticateImpl is null");
  12.         }
  13.  
  14.         return AuthenticateImpl(user, password);
  15.     }
  16. }

Great. We now have a mock class where we provide the implementation of Authenticate dynamically. We can now write some tests for UserManager.Login.

(Assume that the Assert class is part of your preferred unit testing framework, and provides methods used to pass or fail tests).

  1. class UserManagerTestFixture
  2. {
  3.     public void TestLoginSuccess()
  4.     {
  5.         var mock = new MockUserAuthenticationProvider
  6.         {
  7.             AuthenticateImpl = (u, p) => true
  8.         };
  9.         var um = new UserManager(mock);
  10.         Assert.IsTrue(um.Login("User", "Password"));
  11.         Assert.AreEqual("User", um.CurrentUser);
  12.     }
  13.  
  14.     public void TestLoginFail()
  15.     {
  16.         var mock = new MockUserAuthenticationProvider
  17.         {
  18.             AuthenticateImpl = (u, p) => false
  19.         };
  20.         var um = new UserManager(mock);
  21.         Assert.IsFalse(um.Login("User", "Password"));
  22.         Assert.IsNull(um.CurrentUser);
  23.     }
  24.  
  25.     // Test fails for now, we've not specified what happens when
  26.     // we get an exception from our IUserAuthenticationProvider.
  27.     public void TestLoginException()
  28.     {
  29.         var mock = new MockUserAuthenticationProvider
  30.         {
  31.             AuthenticateImpl = (u, p) => throw new NotWorkingException()
  32.         };
  33.         var um = new UserManager(mock);
  34.         um.Login("User", "Password");
  35.     }
  36. }

There. We’ve now got good test coverage of UserManager, and can see that it’s doing its job with regards to the CurrentUser property for two cases. We can now specify and fix up the third case, get this stuff reviewed by a colleague and get it checked in, with the confidence of knowing that UserManager will interact correctly with those third party web services.

Conclusion

Unit testing is an extremely important part of software development today. Writing code that is unit testable can be a challenge, but unit testable code is often extremely versatile, modular and more likely to be correct. This article has shown how to decouple an application and any web services it might access, and how to mock a web service so that code which interacts with that web service can be properly unit tested.

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • LinkedIn
  • Technorati