Skip to main content

From crappy to happy - dependency what, now?

Following the introduction on this series on a previous post, we will now talk about dependency injection and how it has the effect of allowing for more testable code. Sometimes when I talk about this concept it is difficult to explain the effect that applying it might have on the tests. For that reason I think it is better to demonstrate with a near-real-world situation.
Obviously, keep in mind this is not real code, so don't worry about the design or implementation details that don't contribute to the point being discussed.

The code


As you can see, it is simple. There's a class called ShipManager (what else?) that receives position updates for the ships. It keeps the last position reported from each ship and does some calculation to see how much the ship moved. It assigns some values to the update and finally it persists the final version of the update.

How do we start testing?

When you think about it, tests are dead simple. A test either passes or it doesn't. I'm going to focus in unit tests here, and we could use a lot of frameworks like NUnit, XUnit, etc. Sure, we can introduce the whole plethora of tools that exist at the whim of a single command, but what is the simplest thing we can do to test our code? Check if true or false!

Since I want to keep this minimal, the tests in this series will be a matter of asserting a few conditions and printing true or false. This is not production code, but it provides a low barrier of entry for everyone.

Here is the example of a test:

Questions I want to answer with tests

Looking at how the code behaves, there are some immediate tests that we could write:
  • Is the distance calculated correctly from the previous position?
  • Does the manager persist the position?
  • Does the manager correctly calculate the expiration date for the position?
I will answer the first one, but after that I think the way to answer the other ones should be easy to understand.

 Why is the code not testable? 

There are multiple kinds of tests. We will focus on unit tests. These kinds of tests tend to be small, isolated and test a single behavior only.

I am instantiating the ShipPersistenceService and DistanceCalculator in the constructor of ShipManager on purpose. This makes it very difficult to build a unit test that tests a behavior in isolation, because then the ShipPersistenceService would need to have a database - or other persistence medium - set up in order to run the test. Also, how would I be able to get the distance that the calculator returned? Maybe use the fact that it mutates the update itself? That's crappy, but this kind of problem comes up very often in codebases. Here is the test that we will make possible:


Notice that both ShipPersistenceService and DistanceCalculator are used by the ShipManager in the PositionReceived method, so we could say that ShipManager depends on them to do the job. These two classes are dependencies that are being created in the constructor, but doing that is preventing us from isolating the ShipManager logic from it's dependencies.

Wouldn't it be good if we could just swap in fake dependencies? Then when we run the tests we wouldn't have to deal with the database. What if we could... like... inject dependencies? Yeah, that's an incredibly original idea. So we make a simple change:

Now we are using proper Dependency Injection. Notice that this does not yet achieve our objective, but we now are required to pass the dependencies as a parameter when creating a ShipManager in the test. We have control of those dependencies in the test, but not yet how they behave. We can easily change that using inheritance by marking the methods as virtual and then overriding the behavior in a test implementation that we then inject. And thus is born the mock. And what are mocks? They are fake implementations of the dependencies and serve the sole purpose of helping us testing. Here are the mocks for this case:



Notice that the mocks add a little something of their own. The ShipPersistenceServiceMock is recording the last ShipPositionUpdate it was called with. This will allow us to read it in the test. The DistanceCalculatorMock allows us to set the DistanceToReturn which is returned to the ShipManager. Let's see how to use these new capabilities for the test:


The fact that we can simply set the values we want the methods to return and also record the parameters is a really nice property we will be using A LOT. Almost every single unit test makes use of these features.

Who creates the dependencies now?

Since we are moving towards dependency injection now, who is responsible for creating he dependencies for each class? That is the topic for a whole other post, but the basic answer is: not the class that depends on them. You want to move the instantiation up. Once you start using this pattern you would normally start using in Inversion of Control Containers such as Unity or Ninject. There you can define the graph of your dependencies and assign scopes to each class. That is widely out of scope though.

For the tests, I find it better to just create the dependencies by hand and inject directly. This allows for easy to read tests that are also self contained without messing with IOC containers. Remember, your unit tests should be dead simple without too much of a hassle to run.

Recap

We applied the concept of dependency injection to code that had some dependencies. Coupled with some minor changes and the creation of mock objects, we were able to transform untestable code into testable. This technique is generally easy to implement, but on real code some issues will arise because the dependency graph is much more complex.

As for the way of using mocks, there are a lot of ways of doing this. Given the small context of the article, using inheritance was the easiest one to demonstrate. The most common way is to define interfaces for your dependencies and then depend on those interfaces instead of depending on the classes directly. You would then register these interfaces with your IOC container and define which specific type should be injected.

So this is it for this article on the From crappy to Happy series. Next up we will be dealing with a very common problem: that DateTime.UtcNow that I ignored can have some weird effects on the tests!

Comments

Popular posts from this blog

The repository's repository

Ever since I started delving into architecture,  and specifically service oriented architecture, there has been one matter where opinions get divided. Let me state the problem first, and then take a look at both sides of the barricade. Given that your service layer needs to access persistent storage, how do you model that layer? It is almost common knowledge what to do here: use the Repository design pattern. So we look at the pattern and decide that it seems simple enough! Let's implement the shit out of it! Now, let's say that you will use an ORM - here comes trouble. Specifically we're using EF, but we could be talking about NHibernate or really any other. The real divisive theme is this question: should you be using the repository pattern at all when you use an ORM? I'll flat out say it: I don't think you should... except with good reason. So, sharpen your swords, pray to your gods and come with me to fight this war... or maybe stay in the couch? ...

Follow up: improving the Result type from feedback

This post is a follow up on the previous post. It presents an approach on how to return values from a method. I got some great feedback both good and bad from other people, and with that I will present now the updated code taking that feedback into account. Here is the original: And the modified version: Following is some of the most important feedback which led to this. Make it an immutable struct This was a useful one. I can't say that I have ever found a problem with having the Result type as a class, but that is just a matter of scale. The point of this is that now we avoid allocating memory in high usage scenarios. This was a problem of scale, easily solvable. Return a tuple instead of using a dedicated Result type The initial implementation comes from a long time ago, when C# did not have (good) support for tuples and deconstruction wasn't heard of. You would have to deal with the Tuple type, which was a bit of a hassle. I feel it would complicate the ...

C# 2.0 - Partial Types

For those of you interested, i found a very interesting list of features that were introduced in C# in  here . This is a very complete list that contains all the features, and i'm explaining them one by one in this post series. We've talked about  Generics  and  Iterators . Now it's time for some partial types . A partial type  is a type which definition is spread across one or more files. It doesn't have to be in multiple separated files, but can be. This is a very simple concept that can give us many benefits, let's see: If a type is partial, multiple developers can work on every part of it. This allows a more organized way of working and can lead to production improvement.  Winforms , for example, generates a partial class for the form so that the client can separately edit other parts it. This way, a part contains information about the design and the other contains the logic of the form. In fact, this is a very spread pattern across .Net. Ent...