Dependency Injection by Extension pattern

The problem

You need to use some kind of Dependency Injection (DI for short) to provision some System Under Test (SUT for short) in tests you’re writing, but can’t or don’t want to use a DI framework to do so.

Alternative titles for this post include:

  • Dependency Injection without a Dependency Injection framework
  • Why misusing the default namespace for tests is evil
  • Make code more testable without completely messing it up

I’m not sure whether I have indeed invented a new design pattern here. Read on and let me know.

Don’t expose your privates

Of course, the simplest form of DI is simply passing things to a constructor. But you probably don’t want to code every class to be handed every dependency at construction. And you definitely don’t want to expose the private parts of your implementation through some unnecessary interface – no, you really don’t.


 

I’ve seen scary examples of what I call ‘keyhole surgery’ on classes, either by abuse of the internal/default namespace to allow poking into otherwise private implementation, or just by making too many things public. Although the internal/default namespace is perceived to retain a sufficient level of encapsulation, it really doesn’t. Anything in the same package can jump all over it, so it’s somewhat of a loose interface. As such, you should also never leave methods unscoped, which will usually compile to the internal/default namespace. You should also really reserve the internal/default namespace for when you are in control of all classes that will exist in the same package, such as when creating utility packages.

Loose interfaces are bad practice, for several reasons:

  • Clarity – Anyone using the class will be confused as to the intentions of its interface
  • Cleanliness – Code for tests does not belong in your production code
  • Stability – A class with a loose interface is open to misuse and a recipe for failure
  • Testability – You should test a class through its interface, not its implementation
  • Flexibility – It is hard to refactor classes that ‘leak’ implementation detail

The solution

Well, this is one possible solution and ultimately just my suggestion. It’s especially useful when needing to refactor classes with overuse of the internal/default namespace, since you won’t need to change much test or production code. I call it the Dependency Injection by Extension pattern.

How it works

In short, you provide DI helpers as protected methods in your SUT and subclass it from within your test case, as a script-level class, to expose the DI helpers as public and/or use the constructor to do some of the DI legwork – allowing you to inject mocked dependencies for your tests, etc. This has the advantage of not allowing anything else to meddle with your SUT, other than through its interface. And, if anything in your production code wishes to extend your SUT, potentially overriding and messing up the interface too, then that class should have its own tests anyway. Simples!

Example

The following example shows a very basic class (SystemUnderTest) being extended from within its test case (SomeTest) to allow injection and access to its dependencies, for the purpose of verifying its behaviour under given conditions.

Hopefully it’s self-explanatory. You may also notice that changing classes which had unnecessary internal/default exposure becomes a simple search and replace exercise. Let me know if you’ve heard of this before, if you have any suggested improvements/alternatives or other questions. Happy testing 🙂

InterServer Web Hosting and VPS
 

Leave a Reply