Simple Injection Example
by Joseph on Jan 29th in .Net, Architecture, C#
Today I was asked an interesting question: how do I test a method which writes to a database, without writing to the database. My answer, of course: “Interfaces”!
But… what if you don’t know HOW to do interfaces?
My goal in this post is to explain Dependency Injection and Inversion of Control without actually using the words “Dependency Injection” or “Inversion of Control”. Why? Because when I was first learning the concept, I found that many authors got so caught up in describing the broad concept, they never got around to explaining the simple step of “How”.
All of this code will be available on Github at https://github.com/jmreynolds/SimpleInjectionExample. I’ll also throw a few Gists in here to highlight some cool bits.
Warning:
This blog post turned out to be a LOT longer than I originally intended. If you’re just looking for a road-map, try poking at the GitHub stuff. I tried to be pretty obvious about where I was going. For the details, read on.
Use Case
In our example, we will be examining the use case of writing a Person to a database, then, in our test, reading the database to ensure that the person was written correctly. The person should look something like this:
[gist id=”a915ee8e69459efe8f16″ file=”Person.cs”]
First Pass
Let’s start simple. Normally, the first pass through is generally a somewhat naive, or optimistic approach. In our example, we will be writing the person to our localDB, then reading the person back, and displaying the result in a console window in order to confirm expected results.
[gist id=”a915ee8e69459efe8f16″ file=”ProgramFirstPass.cs”]
Notice here, we’re directly calling our utility, which we’ve conveniently named PersonService. We’re going to ignore that for now.
Let’s take a look at the PersonServiceFirstPass class.
[gist id=”a915ee8e69459efe8f16″ file=”PersonServiceFirstPass.cs”]
This is actually not too far off from code I still see every day. Code that was written years ago, is still functioning, and which forms the backbone of businesses across the world.
Before you say anything, let’s start by realizing that this is probably better than some of the code I wrote at the beginning of my career. Remember when people used to mix data access code in the event handlers of WinForms (or worse, WebForms) button clicks? Yeah, I do.
Let’s start with what’s good.
We’ve got a connection string that we’re not using everywhere. It’s obvious that there is some initial work being done here to cut down on code re-use. There’s some parameterization being done in the INSERT and SELECT queries. Perhaps there’s a little more that could be done to ensure SQL Injection safety, but at least it’s not a direct string query.
So it’s not all bad. There’s hope.
What is wrong?
Frankly, there’s a lot wrong with this code. First off – there’s just a LOT of unnecessary database plumbing going on. We’re not going to get in to a big discussion of ORM\Micro-ORM\etc… But let’s at least see if we can offload some of this into some sort of a helper.
Second Pass
Our second pass isn’t going to get much more complex. We’re going to move the bulk of the work into a class called SqlHelper. Initially, this won’t honestly help much.
SqlHelper exposes things like a SqlCommand, and stuff that we really don’t want being visible to our application. But, it gets us moving towards thinking about doing things where they belong. This class, for instance, takes a connectionString as a parameter, and handles making the connection to the database for us. Unfortunately, we still have to provide a SQL query. Like I said, we’re not doing an ORM review.
Here’s the SqlHelper class.
[gist id=”a915ee8e69459efe8f16″ file=”SqlHelperFirst.cs”]
How does this end up getting used?
Here’s a simple example. It implements IDisposable, so we get to wrap everything in a Using statement. Essentially, all we have to do is pass in a SQL query and tell the SqlCommand to execute.
[gist id=”a915ee8e69459efe8f16″ file=”SqlHelperCleanupSample.cs”]
Pretty nice, right?
A quick look at the PersonServiceSecondPass reveals that there really wasn’t a significant change in Line Count, per se. Our primary gain at this point is a little bit more ease of maintenance, and perhaps a more readable codebase.
[gist id=”a915ee8e69459efe8f16″ file=”PersonServiceSecondPass.cs”]
Third Pass
Now we’re going to start pushing some comfort zones. I’m going to change the SqlHelper up a bit so it’s not exposing quite as much directly to the application. This third pass will still be a bit rough, but it’s going to set us up nicely for our next step.
During this pass, we managed to focus on the way the execution of SQL Commands in the SQL Helper was handled.
[gist id=”a915ee8e69459efe8f16″ file=”SqlHelperSecond.cs”]
Notice that at this point, we are no longer referencing System.Data.SqlClient in our Using Statements for our PersonServiceThirdPass.
Here’s a look at the end result. It’s actually starting to look a little better now!
[gist id=”a915ee8e69459efe8f16″ file=”PersonServiceThirdPass.cs”]
What’s going well here?
We’re to a point where the SQL stuff is happening out of sight, for the most part. We still see the actual query, but that’s OK – this is the class that *could* belong in. If you want to stick with low-level SQL, having one class be responsible for the queries related to a piece of your domain isn’t the worst idea in the world.
The SQL plumbing has moved off-site to our home-made helper class. That helps us work towards better SOLID code, and shows a lot of improvement in the codebase in general. This helper we’ve written could be used in other applications via “Copy-Paste-Reuse” and live on for a long time.
What’s going badly
First, the fact that I just used the phrase “Copy-Paste-Reuse”, unironically. Unfortunately, in many projects, this is where it stops. Worse, two or three projects have a SqlHelpers, which probably started off looking the same, but over two or three copies, it has morphed into 3 or more different classes.
Second, we’re still referencing the class directly. There is no way, at this point, to Unit Test the Person Service without committing a change to the database.
Let’s see if we can step this forward just a bit by using an Interface.
Fourth Pass
In this pass, we’ve added an Interface – the first meaty step towards really being able to test this, and resolve the question that launched this article.
[gist id=”a915ee8e69459efe8f16″ file=”ISqlHelper.cs”]
This interface exposes, really, only the three things we use in our code. We should be able to: Execute a bit of adhoc SQL that doesn’t return a result set (ExecuteNonQuery), Execute a bit of adhoc SQL that does return a result set (GetTable), and Add Parameters of various types and have our code figure out what to do with them (AddParam<T>).
The other interesting bit here is the ISqlHelperFactory class we’ve added. This allows us a convenient means for generating a SqlHelper on the fly. In addition, because the SqlHelper is not generated until runtime, we can inject a mocked method to use for things like unit tests.
For now, let’s just look at how this looks in our Console Harness.
[gist id=”a915ee8e69459efe8f16″ file=”ProgramFourthPass.cs”]
The only truly significant change between this and the first run in the Console Harness is the addition of the Factory to the method. We’re now controlling, from outside of the class, what will be used inside of the class for things like database connections.
Now to look at how this is implemented in the PersonService.
[gist id=”a915ee8e69459efe8f16″ file=”PersonServiceFourthPass.cs”]
Notice that the constructor assigns the Injected Factory to a private, class level field. Later on, in the using statements, instead of instantiating a specific implementation of a SqlHelper class, we depend on the factory to know what we want.
In production, we want to factory class to return something that will go all the way through to the Database.
In Integration Tests, we probably want the tests to run against a database, but not the production database. In fact, there may be several “levels” of testing before it hits production:
In Unit Tests especially, writing and reading from a database is typically not particularly desired.
What does the factory class look like? In this case, it’s fairly simple.
[gist id=”a915ee8e69459efe8f16″ file=”SqlHelperThirdFactory.cs”]
Notice anything? We moved the Connection String into the Factory Class!
That’s primarily because I may be interested in creating two or three implementations of the factory, depending on how many levels of testing I’m performing!
Something Different
Now that we’ve got our SqlHelper pretty well turned into a nice, Interface-Based class, let’s try something different. Let’s try skipping the Database altogether.
The first difference to notice here is the Fake SqlHelper Factory class.
[gist id=”a915ee8e69459efe8f16″ file=”FakeSqlHelperFactory.cs”]
We’re doing away with the Connection String entirely. We don’t have any interest in touching the Database, so why put it in?
The other interesting bit is that we’re returning a custom-made Fake SqlHelper. This will be the piece that allows us to bypass the database, but still fulfill “contractual obligations” within the code.
[gist id=”a915ee8e69459efe8f16″ file=”FakeSqlHelper.cs”]
There’s really not much here. The only actual implementation is what’s required to return an expected result in a DataTable when we read from the Database.
Keep in mind – this is a VERY simplistic example. There are much better frameworks out there for mocking out Interfaces on the fly.
At this point, we’re not even going back to the Person Service. It hasn’t changed.
Let’s take a quick look at the Console Harness though.
[gist id=”a915ee8e69459efe8f16″ file=”ProgramFakePass.cs”]
Notice that the only change here is that we’re now using the “FakeSqlHelperFactory” when we set up the Factory Class.
Congratulations! We’ve just taken a typical, old-style .Net app, and introduced the first elements of Dependency Injection!
If we were REALLY ambitious, we could try taking the PersonService class, and making it run against an interface as well. I leave that as an exercise for the reader.
Let’s take a quick look at some Tests now.
Tests
The first set of tests are Unit Tests. In this case, we’re using the FakeSqlHelper, and the database is never touched.
[gist id=”a915ee8e69459efe8f16″ file=”FakePersonTests.cs”]
For reference, I am using NUnit and the Should extensions.
Notice that this validates that the returned person has the same first and last name, no matter what GUID is passed in to the GetPerson method. Consistency! Yay!
However… What if we actually want to test the SqlHelper itself. That, my friend, is an integration test! It is also a Very Good Thing!
[gist id=”a915ee8e69459efe8f16″ file=”PersonServiceIntegrationTests.cs”]
Now, we have something that can be automatically run. If we really wanted to get fancy, we could do things like putting the connection string into a config file that can change based on whether we’re in production, development, or somewhere in between.
Wrap-Up
I hope this has been a little bit useful. There are SO many great frameworks out there that make all of this easy, but to get there, it helps to understand WHY you would want to. And now I’m going to break my earlier stated rule, and use those words I said I wouldn’t use.
If you want to get really serious here, you’re going to want to investigate one of the Dependency Injection containers. I’ve used StructureMap the most, but have been happy with what I’ve seen of Unity and Ninject.
Scott Hanselman has a neat roundup of the popular ones here, but I’m not sure how current it is.
Martin Fowler is one of the most prolific authors on the subject of Dependency Injection, and his articles were a turning point in my personal understanding of the subject. Here’s one of his better ones.
Finally, the code is available on GitHub.
I hope someone gets some use out of this – if so, drop me a line and let me know!