Concrete Dependencies by Mark Seemann

Concrete classes can also be used as dependencies

Usually, when we think about Dependency Injection (DI), we tend to consider that only polymorphic types (interfaces or (abstract) base classes) can act as dependencies. However, in a previous blog post I described how primitives can be used as dependencies. A primitive is about as far removed from polymorphism as it can be, but there's a middle ground too. Sometimes 'normal' concrete classes with non-virtual members can be used as dependencies with to great effect.

While the Liskov Substitution Principle is voided by injecting a concrete type, there can be other good reasons to occasionaly do something like this. Consider how many times you've written an extension method to perform some recurring task. Sometimes it turns out that an extension method isn't the best way to encapsulate a common algorithm. It might start out simple enough, but then you realize that you need to provide the extension method with a control parameter in order to 'configure' it. This causes you to add more arguments to the extension method, or to add more overloads. Soon, you have something like the Object Mother (anti-)pattern on your hand.

A concrete class can sometimes be a better way to encapsulate common algorithms in a way where the behavior can be tweaked or changed in one go. Sometimes the boundary can become blurred. In the previous post I examined constructor arguments such as strings and integers, but what about an Uri instance? It might act as a base URI for creating absolute links from within a Controller. An Uri instance isn't really a primitive, although it basically just encapsulates something which is a string. It's an excellent example of the Value Object pattern, providing a rich API for manipulating and querying URIs.

It can be more complex that that. Consider Hyprlinkr as an example. What it does is to produce URI links to other Controllers in an ASP.NET Web API service in a strongly typed way. It's not really a polymorphic dependency as such, although it does implement an interface. It's more like a reusable component which produces a determinstic result without side-effects. In Functional Programming terminology, it's comparable to a pure function. For a number of reasons, this is a prime candidate for a concrete dependency.

Before I get to that, I want to show you what I mean when I talk about locally scoped methods, including extension methods and such. Then I want to talk about using the RouteLinker class (the main class in Hyprlinkr) as a classic polymorphic dependency, and why that doesn't really work either. Finally, I want to talk about why the best option is to treat RouteLinker as a concrete dependency.

RouteLinker as a local variable

While Hyprlinkr was always designed with DI in mind, you actually don't have to use DI to use it. From within an ApiController class, you can just create an instance like this:

var linker = newRouteLinker(this.Request);

With this locally scoped variable you can start creating links to other resources:

Href = linker.GetUri<NoDIController>(r => r.Get(id)).ToString()

That seems easy, so why make it hard than that? Well, it's easy as long as you have only a single, default route in your web service. As soon as you add more routes, you'll need to help Hyprlinkr a bit by providing a custom IRouteDispatcher. That goes as the second argument in a constructor overload:

var linker = newRouteLinker(this.Request, ??);

The question is: how do you create an instance of the desired IRouteDispatcher? You could do it inline every time you want to create an instance of RouteLinker:

However, that's starting to look less than DRY. This is where many people might consider creating an extension method which creates a RouteLinker instance from an HttpRequestMessage instance. Now what if you need to supply a configuration value to the custom route dispatcher? Should you pull it from app.config straight from within your extension method? Then what if you need to be able to vary that configuration value from a unit test? This could lead toward an unmaintainable mess quickly. Perhaps it would be better injecting the dependency after all...

IResourceLinker as a polymorphic dependency

The RouteLinker class actually implements an interface (IResourceLinker) so would it be worthwhile to inject it as a polymorphic interface? This is possible, but actually leads to more trouble. The problem is that due to its signature, it's damn hard to unit test. The interface looks like this:

That may at first glance look innocuous, but is actually quite poisonous. The first issue is that it's impossible to define proper setups when using dynamic mocks. This is because of the Expression parameter. The problem is that while the following Moq setup compiles, it can never work:

The problem is that the expression passed into the Setup method isn't the same as the expression used in the SUT. It may look like the same expression, but it's not. Most of the expression tree actually is the same, but the problem is the leaf of the tree. The leaf of the expression tree is the reference to the artistId variable. This is a test variable, while in the SUT it's a variable which is internal to the SUT. While the values of both variables are expected to be the same, the variables themselves aren't.

It might be possible to write a custom equality comparer that picks expression trees apart in order to compare the values of leaf nodes, but that could become messy very quickly.

That's not the only problem with the IResourceLinker interface. The other problem is the return type. Since Uri doesn't have a default constructor, it's necessary to tell Moq what to return when the GetUri method is called. While the default behavior of Moq is to return null if no matching Setups were found, I never allow null in my code, so I always change Moq's behavior to return something proper instead. However, this has the disadvantage that if there's no matching Setup when the SUT attempts to invoke the GetUri method, Moq will throw an exception because there's no default constructor for Uri and it doesn't know what else to return.

...and that's just to prevent the unit test from crashing. Each and every unit test that hits the same method must have this Setup because the SUT method internally invokes the GetUri method four times with four different parameters. This is pure noise and isn't even part of the test case itself. The tests become very brittle.

If only there was a better way...

RouteLinker as a concrete dependency

What would happen if you inject the concrete RouteLinker class into other classes? This might look like this:

What about unit testing? Well, since the GetUri method is strictly deterministic, given the same input, it will always produce the same output. Thus, from a unit test, you only have to ask the instance of RouteLinker injected into the SUT what it would return if invoked with a specific input. Then you can compare this expected output with the actual output.

In this test, you Freeze the RouteLinker instance, which means that the linker variable is the same instance as the RouteLinker injected into the SUT. Next, you ask that RouteLinker instance what it would produce when invoked in a particular way, and since AtomLinkModel doesn't override Equals, you produce a Likeness from the AtomLinkModel and verify that the actual collection of links contains the expected link.

That's much more precise than those horribly forgiving It.IsAny constraints. The other advantage is also that you don't have to care about Setups of methods you don't care about in a particular test case. The SUT can invoke the GetUri method as many times as it wants, with as many different arguments as it likes, and the test is never going to break because of that. Since the real implementation is injected, it always works without further Setup.

Granted, strictly speaking these aren't unit tests any longer, but rather Facade Tests.

This technique works because the GetUri method is deterministic and has no side-effects. Thus, it's very similar to Function Composition in Functional languages.

Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.