These days you’ll often here people talking about TDD (Test Driven Development) and you’ll hear about extensive use of unit testing.
There are lots of tools to help implement unit testing and TDD for different languages. Ruby has
Test::Unit built in. Java has JUnit, and .NET has NUnit. And ColdFusion has cfcUnit and – the subject of this post: MxUnit.
In work we use an agile development process (thought not true scrum) and we have traditionally done very little structured testing. We did test new and modified code (of course) but not in a methodical way that ensure we gave ourselves the best chance of finding all bugs prior to user acceptance testing and deployment.
Once of my colleagues in work, Barry Jordan, start to use MXUnit for some projects over a year ago. I recall a few years ago reading this article about using TDD with ColdFusion but I was always a little fuzzy about how to start using it, especially on a code base that’s over 10 years old (in places) and has over a million lines of code!
I changed my mind over Christmas when I contributed to cfmongodb – the CF MongoDB drivers. Mark Esher, the project lead, asked me to write some tests for my contributions and I realised how important a maintained set of tests is for a library like this. My interest was piqued and I decided to look out for a suitable project in work.
So recently in work I was asked to create an set of web service calls for a third party. The third party wanted an API they could use to insert transactions and retrieve player information from our system. We do these kind of APIs pretty often, but the trick this time was to use MXUnit and TDD development.
The reasons I choose this particular project to try out MXUnit was becuase the scope of the implemention was limited, I was creating about 10-20 objects and I had a very particular API to implement. There were a set of objects to be implemented that had strictly defined inputs and outputs – this made it easier to know what to test.
In fact as a general rule, APIs like this are a great place to start with MXUnit and TDD.
In order to cater for TDD you need to code a little differently from the start. I tried to just do it normally, but I found that a few simple rules of thumb made things easier:
- You need to write well structured OO code.
- Functionality should be broken down into as small components as possible, and often this means functions. This means these functions can be ‘mocked’ where necessary.
- It’s helpful to throw particular exceptions for error states. These will bubble up and can be caught by the test framework and tested for.
The way I implemented the API was as follows:
- I needed to cater for a number of request types with a number of corresponding response types.
- I created a factory object that created a
Responseobject of a particular type.
Responseobject implemented the same interface. Each returned an XML object. They accepted the request parameters and stored them internally as CFC property, called
validate()on the data and called
process()on the data to return the XML data.
- I was able to write a test for every
Responsesub-class that tested the
process()for a given set of parameters.
This worked really well. I was able to use MXUnit’s injectMethod() function to replace functions in my
Response instance that queried the database and returned query objects. I mocked up these queries in the injected method with the CF QuerySim custom tag.
In the end the API was changed a number of times, and when it did I made my changes, ran my tests and fixed the fails. This gives the developer great confidence that the changes are correctly tested and the whole API is still working fine. Also the MXUnit Eclipse plugin is rock solid and makes it really easy to integrate the testing into your development environment.
The drawbacks as I see it (so far) is the fact there is extra coding involved! You also have a maintenance cost in maintaining the tests into the future. This needs to be done, no matter who works on the base code next. This is the cost of more robust production code. With that in mind, unit testing and use of MXUnit needs to be adopted by the team to be effective.
The bottom line is that I’ve found TDD and MXUnit a positive experience. For you to enjoy it you need to start small, break everything you need to do down into units and manage the scope of what you are trying to achieve. Good luck!