1

Suppose I have an interface declaring the following method signature:

SearchResults SearchProducts(string type, string filter, string anotherFilter);

Inside a concrete implementation of this, I instantiate a helper class (call it QueryBuilder), built to ease the construction of strongly-typed search queries for the specific search library I'm using. I want to unit test SearchProducts (ideally by mocking the query builder), which means I need to decouple the method from QueryBuilder.

How do I do this appropriately when the two things are logically coupled? That is to say:

  • It's not appropriate to pass an IQueryBuilder into the method as the implementation of IQueryBuilder is tightly coupled to the implementer of ISearchProducts, i.e. the types of the return values of QueryBuilder's methods are specific to the library being used in the concrete SearchService.
  • It's not appropriate to pass an instance of IQueryBuilder into the SearchService constructor (via DI or directly) as the logical scope of the query builder instance is local to the SearchProducts method call - it is instantiated in the method, its state is manipulated by adding sub-queries and a complete "query" is extracted for this SearchProducts call).

So, given the above, what's the appropriate way of handling this? It sounds like a case for a factory; however the implementation of this factory would be trivial and it seems a little contrived to define a factory interface and add a constructor parameter just for the sake of testability.

Is this indicative of a fundamental flaw in the design of my search interface? How do I decouple these things appropriately such that I can test both the search service and the query builder implementations in isolation?

2
  • 2
    That you're using QueryBuilder is an implementation detail. You can produce equally valid implementations that don't use it. So I wouldn't mock it, even if it increases the size of the system under test. Jan 29, 2014 at 22:30
  • @CodesInChaos I had considered that, but QueryBuilder has methods with logic sufficiently complex that I would like to test it in isolation, which means that not mocking it undermines the usefulness of testing SearchService, no?
    – Ant P
    Jan 29, 2014 at 22:33

1 Answer 1

4

This is the ideal use for Inversion of Control, or specifically, Dependency Injection. In your test context, your query builder is the mock; in your normal execution context, it's the real deal. No need for a factory, just a different context.

3
  • That's all fine; except, as I said, the logical lifetime of the QueryBuilder is within the method - it's instantiated within the method, its state is manipulated with in the method and it is destructed within the method. Use of DI (be it parameter or constructor injection) would imply a query builder per search service instance, which does not make sense given the functionality of the query builder.
    – Ant P
    Jan 29, 2014 at 21:57
  • This is why a factory seems more appropriate - inject the factory and let the method instantiate the query builder. But it also seems overengineered.
    – Ant P
    Jan 29, 2014 at 22:03
  • 1
    That seems reasonable. Alternatively, you could separate the QueryBuilder state from the QueryBuilder logic, like (N)Hibernate does with its Criteria class. Then you could have a longer-lifetime QueryBuilder that is injected and re-used, and a per-method Criteria that is passed between QueryBuilder methods and the calling class.
    – Paul Hicks
    Jan 29, 2014 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.