The coding blog of Alastair Smith, a software developer based in Cambridge, UK. Interested in DevOps, Azure, Kubernetes, .NET Core, and VueJS.
One of the reasons progress on my web frameworks’ evaluation has been so slow of late is that my last check-in broke my CCNET automated build, and, as the good programmer I am, I felt that this needed fixing before I made any more progress.
I’d written some unit tests for the PostController
(good) that were accessing the database directly (bad), and for whatever reason the build machine couldn’t successfully connect to the database. A classic case of “works on my machine!”, and, as is usually the case with such things, a good example of poor design.
First off, my tests were reliant on an external resource to run. This is not a good thing, as it increases the scope for things to go wrong (as I found out to my cost), and in such a way as to reduce the amount of control the developer has over his tests. Doubly bad.
From there, it also pointed to poor design. The PostController
knew about the database, intimately. There were methods liberally sprinkled with SQL; the PostController maintained a connection to the database, including a hard-coded connection string. In other words, it was all horribly, horribly wrong.
I quickly came to the conclusion that I needed a Data Abstraction Layer (DAL) that would allow me to mock the database in my unit tests. My first port of call was to investigate Object-Relational Mapping (ORM) solutions. As usual, my trusty Stack Overflow came to the rescue, with a whole host of questions on ORM; “Whose Data Access Layer do you use for .NET” and Best Performing ORM for .NET proved particularly instructive. Frameworks like NHibernate, SubSonic, and Castle ActiveRecord all seemed very good, and particularly feature-rich, but they all seemed far too heavy-weight for my slim and floaty-light blog application. They were all filed under “E” for “experience” and “F” for “future”.
One response to a Stack Overflow question suggested looking into the Repository Pattern, as described by Martin Fowler in his book Patterns of Enterprise Architecture. Like all good design patterns, the Repository Pattern describes a simple solution to a common problem. A repository is provided for each data type stored (e.g., posts, comments, users, etc.), and an interface is defined for each repository providing basic CRUD support. This interface is then implemented for each concrete implementation required. The original pattern seems to provide in-memory and persisted implementations, whereas I only really needed the persisted implementation.
So, I defined my posts’ Repository:
MySqlPostRepository
:
MySqlPostRepository
in my Trac environment for the project.
This re-implementation led to a much nicer set of unit tests for the PostController
:
Save()
test is still being re-written as some of the test cases I had are no longer valid with the new architecture. However, the TestReadViewData()
test provides a fairly instructive example.
Before each test is run, the SetUp()
method is called, which creates two Post
objects, newestPost
and post2
. These are "mock" objects for the most recently submitted post and the second post submitted respectively. I use the term "mock" loosely - they're not mock objects in the usual sense of the word (as we'll see shortly), but they are fake posts that we expect to see returned from the mocked IPostRepository
. The SetUp()
method then creates three stubs on IPostRepository
, two for GetPostById()
and one for Save()
. The stubs expect GetPostById()
to be called with the argument -1 (a brand new post that hasn't been saved to the database yet, in which case it should return the most recent post, defined as the post with the highest ID), and with the argument 2 (which should return the specific post with ID = 2). The stub on Save()
doesn't do anything at the moment, as per my previous note about the Save()
method. As you can see from the example above, the NMock framework produces a very nice syntax for defining stubs and expectations, which I go into more detail about in my previous post on NMock.
Note also that there is an element of dependency injection here, specifically constructor injection: the PostController
now needs to be passed an IPostRepository
at construction. Dependency Injection is a form of inversion of control, and decouples PostController
from the IPostRepository
implementation, all Good Things™. This allows me to fully test the PostController
's interactions with the IPostRepository
without requiring a database to be present. What it can't do, unfortunately, is allow me to test the MySqlPostRepository
without a database. That might need something more inventive, or just not be part of the CCNET build.
My next step is to re-factor the IPostRepository
interface into a generic IRepository</code> interface so that I don't need to define a new repository interface for each data type. Luckily, the interface is already generic enough (aside from method names) to allow me to accomplish this quite easily.