Unit Testing and TDD – A Practical Experience

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 Response object of a particular type.
  • Every Response object 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 Response sub-class that tested the validate() and 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!

About these ads
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

7 Responses to Unit Testing and TDD – A Practical Experience

  1. stefanhendriks says:

    In fact, if you would TDD you literally start with a test without any production code backing it up. This would make your code not compile. Only then you would write the bare minimum to make your test pass. And so on.

    This might seem like a little overhead and stupid. But it is not. In fact, with your requirements at hand you are creating exactly an interface that you need for your client. Also, you will be testing cases where things are unexpected. For instance, your request object is null or invalid.

    Robert C Martin once said (don’t know where though) that you will probably write as much test code as production code (50/50). But your code will be much cleaner, it will be tested and its design will be better.

    I’ve now tried this myself for over half a year and it really does work. In my case I have worked on implementing a Webservice (not creating one). And I have not seen a single bug yet coming back. Normally such integration features come back often with silly bugs. Now it just worked. I am all for TDD :)

    • ciaranarcher says:

      Hi Stefan

      Can I ask what approach you take to simple vanilla scripts that submit to a controller and call a service for results. I haven’t been using TDD for these as they aren’t encapsulated etc. so I end up just testing my service layer objects. Is that your experience too?

      Thanks.

      • stefanhendriks says:

        I would TDD my services, as I can simulate a request came in. I also would TDD the controller. You can stub all collaborators the controller uses and test if the outcome is as you would expect.

        I’m not sure what ‘vanilla scripts’ are, so I can’t really answer on them.

  2. ciaranarcher says:

    I guess the important prerequisite to undertaking TDD is to ensure that you are using proper encapsulation and OO programming. Ideally some sort of MVC framework too. I work on a large website that contains scripts that are not part of any framework (these are the vanilla scripts I spoke of!). These scripts mix presentation code and database logic and are therefore poor candidates for TDD. They will be re-written in time, but it’s important, I think, to ensure that you have a good environment and practices in place before starting TDD development. Otherwise it might not even make sense, never mind work.

    • stefanhendriks says:

      Actually, the vanilla scripts are poorly designed. TDD will help you prevent that by identifying collaborators. You would have identified some view layer and a data layer.

      However, the since scripts already exist. This does not mean you cannot TDD other parts of the system or entirely new features.

      I consider a good environment to be:
      – an environment where you can run unit tests
      – an IDE which helps you write and run tests fast
      – having a build system (CI)

      But you’re right, TDD cannot be used for existing code directly. It takes courage to change existing (legacy) code without knowing if it will keep working. Intergration tests can be your friend there. (just check if the outcome remains the same).

  3. ciaranarcher says:

    Yes, I agree 100%. It does take courage to go ahead with it for new parts of the system or re-factoring of older parts. Next step: encourage the team to take up the challenge :)

    • stefanhendriks says:

      In my experience, showing the benefits of (small) refactorings to improve the design is very rewarding. Also other developers will see the benefits and want to see/learn more. Its a slow process but rewarding in the end.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s