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

From crappy to happy - refactoring untestable code - an introduction

I started testing my code automatically a couple of years in after starting my career. Working in a small company, there weren't really incentives for us to automate testing and we were not following any kind of best practices. Our way of working was to write the code, test it manually and then just Release It ™ , preferably on a Friday of course. I'm sure everyone can relate to this at some point in their career, because this is a lot more common than the Almighty Programming Gods of the Internet make us believe. I find that the amount of companies that actually bother writing tests for their production code is a fraction of the whole universe. I know some friends who work in pretty big companies with big names in the industry and even there the same mindset exists. Of course, at some point in time our code turned into a big pile of shit . Nobody really knew what was going on and where. We had quantum-level switcheroo that nobody really wanted to touch, and I suspect it i...

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? ...

My simplest and most useful type

I have been doing some introspection on the way I write code to find ways that I need to improve. I consider this a task that one must do periodically so that we keep organized. There is a very, very simple problem that occurs in every application I know: How to return the results of an operation to the user? I've seen many implementations. Some return strings, some throw exceptions, some use out parameters, reuse the domain classes and have extra properties in there, etc. There is a myriad of ways of accomplishing this. This is the one I use. I don't like throwing exceptions. There are certainly cases where you have no choice, but I always avoid that. Throughout my architectures there is a single prevalent type that hasn't changed for years now, and I consider that a sign of stability. It is so simple, yet so useful everywhere. The name may shock you, take a look: Yes, this is it. Take a moment to compose yourself. Mind you, this is used everywhere , in every ...