Mar 11, 2013
Table of contents:
Over the past couple of years, there has been a strong shift in the development community to move towards Continuous Integration. Continuous Integration (CI) is where a team of developers will push changes or new features multiple times per day. The benefits of rapid deployment is that new features and fixes can be applied to the production server much quicker.
In the fast paced world of software development, there will always be bugs in code. When you are deploying to the live server multiple times per day, you increase the likelihood that you have introduced a bug in new code, or you have broken something in the existing architecture.
One of the key components of Continuous Integration is having automated tests run through your code to check that everything is working as it should.
Setting up tests for code that you have already written can seem laborious and time consuming. Test Driven Development (TDD) is a software development process that promotes writing tests from the outset.
In this post I will introduce the concept of Test Driven Development, how it works and why you should consider changing your workflow.
Whilst there is far more to Continuous Integration than a testing framework, it is an important first step if you want to move your software into a more stable and fast moving architecture.
Test Driven Development (TDD) is the process of writing tests during the development of software. Typically, TDD will break each task of the development into individual units. A test is then written which will ensure that the unit behaves as expected.
Over the course of developing the software, the developer will build up a framework of tests for each individual component of the architecture. These automated tests can be run periodically to ensure that each individual component is still behaving as expected.
Whilst Test Driven Development makes the actual writing of code slower, there are a number of advantages to taking this approach.
Firstly, you ensure that your code is working exactly how you mean it to. Often code will seem to work correctly, when in fact there is some underlying reason why it will fail under a certain condition. Test Driven Development looks to remove this problem by ensuring that each individual component is working correctly.
Secondly, testing an application through a browser can be extremely time consuming and it’s pretty easy to overlook or miss a serious bug. Test Driven Development enables you to set up test cases to test each element of validation, database requesting and all of your business logic so that each individual component gets tested.
And thirdly, when you come to make changes to your code in the future you could unwittingly make a change that breaks another mission critical part of your application. When making changes, you are only going to be manually testing the areas of the software that you think you will have effected. It’s really easy to forget about some underlying structure once an application becomes complicated. Test Driven Development will highlight exactly where something has broken, and allows you ship your latest release without worrying that you have left something broken.
An excellent analogy for Test Driven Development is, TDD is like brakes on your car. Without breaks on a car, you would be forced to drive really slowly. However, because breaks allow you to control when you stop, it allows you to drive much more freely. Test Driven Development removes all of the stress of shipping broken code, and allows you to get on with the job of improving your application.
The Test Driven Development cycle is a bit of a departure from the normal way of writing code so it can take some getting used to.
Before you write any actual code, you need to write your test so you can watch it fail. Writing the test first ensures that you can confidently say that you made the test pass for the right reasons.
At this point it’s pretty obvious it’s going to fail because there is nothing to test! This incremental approach keeps you on the right track of breaking each component down in to it’s smallest unit.
Now you need to write the bare minimum amount of code to make the test pass. It’s important that you only write enough to make the test pass because you will need to write additional tests for any additional code you write.
During the process of writing code in Test Driven Development, you will probably need to refactor your code every so often. Writing code that makes tests pass isn’t always as optimum as it could be.
Every so often, loop back and evaluate how you can rewrite something to improve it and keep it DRY. Fortunately you don’t have to worry about breaking any of your code during refactoring because you can just run your tests again.
As with just about everything, Test Driven Development introduces terminology that you may be unfamiliar with. It’s difficult to understand something if you don’t understand the terminology and so here is an explanation of some of the common terms that you will come across.
As covered above, Unit Testing is where you break down you code into small individual components that can be tested independently. By testing each individual component, you ensure that your tests are passing because the unit is behaving correctly and not because it is tied to another unit of code.
Once you have a number of Units that have all been individual tested, you can put them all together and test them as a group. This is known as Integration Testing. This ensures that all of the individual components are working together correctly.
Finally Validation Testing is usually the process where your code is given to software testers to ensure that the feature is working as intended. This can often be achieved by doing sanity checks within the browser.
In complex applications, it’s rare to find components that aren’t tied or coupled to other components in some way. Often the part of the code that you want to test is dependent on some other part of the code.
For example, when you are testing returning results from a database, you will need to test the Model independently from the Database.
A Test Stub acts as a replacement to the dependency. This allows you to test your code without having to actually make real calls to a database.
Similar to Test Stubs, Mock Objects act as a replacement for dependent objects when running Unit Tests. Mock Objects are useful when you want to simulate a state of your application that can only be achieved with the presence of certain Objects.
For example, say you had integrated Twitter into your application and you need to simulate interaction with Twitter without having to actually make a connection for each test. Instead, you could create a Mock Object that would simulate the interaction with Twitter and allow you to Unit Test your code without depending on the external service.
Deploying from a Build Server is a common approach taken by larger application projects. Essentially a Build Server is just a dedicated server the manages deploying changes to production.
When you have many developers working on a project together, each developer’s environment can slightly differ. Having a Build Server ensures is a last level of defences for catching bugs.
For a more in depth explanation of why Build Servers are important, take a look Daily Builds Are Your Friend by Joel Spolsky.
Test Driven Development can seem like a big departure from your current workflow as you need to introduce a significant amount of extra work just to write code. However, when you come to work on big projects and collaborate with other developers, writing tests starts to become a necessity.
Test Driven Development shouldn’t completely slow down your productivity. Finding the right balance of writing tests and writing code is important to ensuring that you can actually get work done and ship your product.
But it’s hard to argue against being able to quickly test your entire codebase to ensure that everything is working correctly.