Mocking the “unmockable”

Recently I’ve had this idea that came into my mind while working on the Sentry – let the users of my library (if there will be any) to configure not only the set of rules, connection strings, urls etc. but also the underlying providers that do all of the heavy lifting (e.g. the HttpClient responsible for communicating with the API). It means that as long as you’re not satisfied with the default solution, please feel free to provide your own engine that will for example talk to the database and perform a query on it. And that’s one part of the story, however, even the more important thing to do was to test that behavior – I had to be sure that would work. So how can we test the classes (I’m talking mostly about the integration testing), that hardly implementy any interface (pretty much none) such as the mentioned above HttpClient? Actually it turned out to be quite simple with the usage of the Wrapper pattern.


 

At first let’s start with the HttpClient. I wanted a new option for the website watcher that would allow to swap the default usage of the HttpClient. First thing to do was to identify the behavior – what do I really need from this class (properties, methods)? Given the fact that it is one of the simplest watchers in the Sentry project, it turned out that I needed just these 4 things:

Now, my configuration does not use the HttpClient anymore but rather the interface defined above (I’m using the Func as a simple way to mimic the factory):

What is the benefit? Well, now it’s quite easy to pass your own implementation of that interface and for me – to do the testing:

Now let’s jump into a little bit more difficult example. There’s this MSSQL watcher for monitoring the database. It uses the IDbConnection and the Dapper on top of it. The good thing is, that it’s already an interface. On the other hand, the Dapper provides a set of the extension methods to the IDbConnection– which is not good in terms of testing. What can we do about it? Let’s extract the interface that will be called directly, instead of making use of the extension methods:

And now my configuration has the following properties:

And the MSSQL watcher can be tested in a following way:

I’ve found these approach to be quite useful. Of course, it’s probably not a good idea to extract the interface for all of the properties/methods of an external class/library. However, in the examples above, I’ve only needed a small subset of these functionalities, therefore it was pretty straightforward (and not too messy) thing to do.

5 Comments Mocking the “unmockable”

  1. Pingback: dotnetomaniak.pl

  2. Chester

    Nice post, as you’ve pointed out yourself, defining all those interfaces can get really tedious.
    Have you heard of the -humble-object-pattern?

    http://stackoverflow.com/questions/5324049/what-is-the-humble-object-pattern-and-when-is-it-useful

    What if instead of injecting your interface with the fields and method you wanted to use on say HttpClient, you instead injected an interface that just made an external call? For example:

    IHttpService {
    string GetAsync(string url);
    string PostAsync(string url, string body, IDictionary headers);
    }

    Then you (or the person using your lib) can use HttpClient, or WebClient, or whatever teh best things is to use when the .NET 7.0 Framework comes out.

    Reply
    1. Piotr Gankiewicz

      I haven’t heard about this pattern, it’s good to learn the new things everyday :). As for your example I think that you might be right – I’ll take a look and maybe change the current interface. Actually, if you take a look at the IQueryExecutor it seems to be following this humble pattern. Thanks.

      Reply
  3. Chester

    If you find yourself wanting to mock outside of your project, you can run something like this on your box: https://github.com/Matthew-Dove/WebServiceMock.

    Then you can do “integration testing” without having the WEB API calls hit up some external service.

    ps I noticed your using “website.com” in your samples, a safer url to hit for testing is https://www.example.com/, they explicitly allow you to hit their site for this sort of thing.

    Reply
    1. Piotr Gankiewicz

      Didn’t know about this tool, probably because I had no need in the past to mock my own HTTP server – seems useful for the localhost testing. As for end-to-end testing actually I’m using the http://httpstat.us – this “webiste.com” was related to unit tests that use the mock of HttpClient, but thanks for pointing that out.

      Reply

Leave a Reply to Piotr Gankiewicz Cancel reply

Your email address will not be published. Required fields are marked *