Writing Unit Tests is Quick and Easy

Writing a unit test should be done before you write your implementation. It should be quick and easy. Sometimes it may feel like writing your unit test is taking a long time. If you are writing your test first (like you should be) it is likely the time is actually being spent on designing your software, not writing your test, but sometimes the two things are actually the same. I know, crazy. We call it test driven design.

If your test was quick and easy to write the chances are your implementation will be focused, usable and decoupled. It turns out that the only way to write unit tests that are quick and easy to write is to design software which is focused, usable and decoupled. If your test takes a lot of setup (see Excessive Setup in James Carr’s TDD anti-patterns) it is likely that not only is your test difficult to understand but that the code it is testing is too complicated, way to complicated…and pretty much untestable.

Thankfully it’s not that hard to design something which is quick and easy to test if you follow a few simple rules:

  1. Keep your methods short. You don’t need to write long methods, ever, really.
  2. Identify what needs to be done in the method call. Can you separate any of these concerns and give your method a single responsibility?
  3. Always code to interfaces. Test against your implementation but within that class specify all dependencies as interfaces. I can’t believe it’s 2012 and I’m still saying this!

I’m not going to paste a code example here, I’m just going to describe the kind of code I write over and over again. I write a lot of web services. Typically I need to:

  •  validate the inputs according to certain validation rules
  • perform a read/write/delete data from the database based on the inputs.

A design which is hard to test would have my web service method perform the validation then marshal the relevant values into db parameters then call a stored procedure. If I am returning values I need to copy them out of the data reader and into an object.

This design is hard to test because I need to set up my test with a valid request and I need to have a database to hand where my method can execute the stored procedure. Relying on data in a database is difficult for many reasons, though not insurmountable. But this is getting into the realms of integration testing which serves a different purpose than unit testing and this post is talking about unit testing. I could opt to make the db command object a dependency and mock it out for my test. This results in an overly complicated test as I need to set up the mock to handle its parameter collection and also to return a mocked data reader so I can get at the returned data and things start to look a little out of control.

Experience has taught me to do the validation in an IValidator interface. Mine has a method called Validate which takes the object to validate and returns a validation result which tells me if validation was successful and gives me a validation errors message/collection to tell me what went wrong.

Next, as we all know we should access our data via a data access object (dao) or repository or whatever people are calling it these days. So my web service now calls the validator interface to validate its input. If the validation succeeds it passes the relevant values to the dao which returns the data as an object.

So now my test is easy:

  • Create the class being tested. Inject a mock validator and a mock dao.
  • Set up the validator mock to respond to the call on its validate method.
  • Set up the dao to respond to a call to its GetThingById method.
  • Assert that the web service method returns the object which my mocked data access object returned.
  • Verify that my mocks were called.

This is a very quick and easy test to write because the web service method now has a purely coordinating role. We don’t need to set up the request in any particular way because the validation is performed by another interface. We just need to make sure we call it. Similarly we don’t need to marshal any values into database parameters or execute the test against the database, we just need to pass the arguments which are wrapped in the request to the dao interface.

The validator implementation then becomes an algorithm we can test without needing mocks. Given a particular input we expect a particular output. Be sure to test for pass and failure, easy right?

The dao implementation only needs an integration test (at least that’s my opinion). I just want to make sure it can actually connect to the database and execute the procedure. For these types of test I like to start a transaction, insert any test data I might need, execute the dao method under test and then roll back the transaction. My test does not depend on any existing data, it is self-sufficient. The same goes for if you are using an ORM (which I prefer). Whichever data access approach you use try to prepare the test data in the database using something other than the class you are testing for obvious reasons.

So, to recap, use test friction as a way to measure complexity in your design. If a test takes a lot of set up try to simplify your design so that you have small easy to test pieces of functionality. Design orchestrating or coordinating classes to tie these pieces together and write quick and easy tests with mocks to prove not just that your classes work, but that they do so simply and cleanly.

Happy testing!

About maz100

I'm interested in the music called jazz, photography, my wife and two daughters, food, wine, software design and furniture...to name but a few.
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a comment