What is Test-Driven Development?

So what’s your approach to testing? Perhaps you take the easy and obvious approach: Run the program, interact with it and see if it does what you expect.

May be this is fine if you’re learning programming or not doing serious work. But let’s say you’re a professional programmer working on a project for your employer… what are the problems with this approach?

The problems with manual testing

The most obvious one is that it’s repetitive and time consuming, so you don’t bother to test your whole program whenever you make a change. You just test the changes or the new feature you’ve added. After all, that’s where the thrill of programming comes from – seeing your code work how you wanted! But once you’ve seen it work a few times, the thrill wears off… So you don’t test the code you wrote last week.

Once you get into serious software development, there’ll come a time when you’re hit by the shock of finding an old feature of your program has broken! “But it was working before! What on earth happened??” you think. Did something you (or a colleague) changed in the code break previously working functionality? In the industry we call this regression. You fix the bug, and you quickly return to working on that new feature. But soon enough… boom! It’s broken again! “How did that happen??” Again you fix it, but soon enough, there’s another bug! This time it’s in a complete different feature and, frustratingly, the change that cause the new bug was in yet another feature! What you have now is fragile code. And how did you get into this mess? Insufficient testing. And now you have this nagging feeling in the back of your mind that says “will this change I’m about to make break something?”. This isn’t a good position to be in and can suck the joy out of programming.

This is a major issue with this approach to testing (which we might call manual testing). What other problems are there? What if you’re writing an API or code library. How do you test that? There’s no user interface to interact with! What if you’re working on a large application and the feature you want to test is buried deep in the system. You don’t really want to have to wait for the program to load, then login, then find the 5th menu item behind the second sub-menu of the ‘Tools’ menu item before you get to the feature you want to test. This is just dull repetition. Again, it sucks out the joy of programming.

Enough about problems. What’s the solution? This is where test automation comes in. In essence you’re telling the computer how to test your programme by writing tests, in code! Test automation is a big topic and there’s many approaches, but in this article I’ll focus on the most basic, lowest level approach, that we call unit testing.

Unit testing

Unit testing is when we test ‘units’ of code. What is a ‘unit’? A unit is the smallest parts of an application that can be isolated and tested independently. What this amounts to in practice depends on what language you using and other factors, but often it is an individual function or method. The goal is to show that these units of code are correct and to find bugs as early in the development cycle as possible, when they’re easier to fix.

Now imagine you had a unit test for every single line of code in your application. The full suite of unit tests can be ran with a single click of a button and within a second or two get the results are available, telling you whether or not your code works as you expect it to. Can you see how valuable that would be – every time you make a code change you can quickly check whether that change breaks anything. Furthermore, if you’re only making small changes between tests, it’s quick and easy to undo those changes and get back to working state and try again.

Test-driven development

Having 100% code coverage with unit tests might sound far-fetched and idealistic, but it is entirely feasible, with the right technique: test-driven development (TDD). The basic concept is to write a failing, write code that passes the test, refactor the code to improve readability and repeat this cycle in very short iterations, sometimes less than a minute long!

TDD can take some getting used to and when starting out, you’ll likely be less productive than normal. But given time and persistence, you’ll get back up to normal speed. This is important, since one of the primary benefits of TDD is consistent development speed.

Go fast forever

If you want to be able go fast forever, one way is to work alone and develop all the code yourself. That way you know how all your code works, how to navigate and make changes. But we don’t all have the luxury of working alone. Some applications are too big coded by one person – a team is needed. The challenge with team development project is working with code you didn’t write. There’s only one thing worse that someone else’s code – that’s someone else’s bad code. If you want to go fast forever in a team project, you have to have clean code.

Clean code is simply code that’s well structured, easy to read and understand, but it takes thought and effort to write. So how do you keep code clean? Refactoring, which is one of the steps in the TDD cycle. Refactoring is change the structure of the code without changing what it does, and in the process cleans the code. If you’ve gotten used to your code breaking whenever you make a change, refactoring is probably the last thing you want to do, but remember what I said previously about having a full suite of unit tests: every time you make a code change you can quickly check whether that change breaks anything. The result is you can refactor your code with confidence, since you know right away if you break something. Refactoring keeps your code clean and keeps you and your team working fast. The practice of TDD helps ensure your test coverage remains high (ideally 100%), so you can keep refactoring your code to keep it clean. And clean code is a joy to read and manipulate!

Summary

There’s much more I could write about TDD. I’ve explained why you should do it, but I’ve not really explained how. I might do this in a future article, but in the meantime they are plenty of other good teaching resources on TDD.

In summary:

  • By writing tests first, TDD helps us create a comprehensive suite (high test coverage) of automated tests that beats manual tests hands down for speed and efficiency.
  • A comprehensive test suite enables a development team to make changes with confidence, enabling safe and continuous refactoring, resulting in clean code.
  • Clean code allows us to make changes fast, so we go fast forever!

Links to more on TDD

Thanks for reading to the end of my very first article on the topic of Unity game development using a test-driven development approach. Before you go check out the list below of other resources on the net that helped me write this article.

If you can’t wait to get started learning TDD, here are some very useful tutorials on the practice:

Also, please leave a comment on what thought of my article. Was it interesting? Did you enjoy/understand it well? Did I explain terms and concepts clearly enough? I’d love to hear your thoughts!

Published by Dan Stevens

Programmer, musician, missionary and follower of Jesus Christ. My foray into full-time missionary career was interrupted by the COVID-19 crisis. In the meantime, I write a blog about my learning experience game development with Unity using a test-drive development approach.

One thought on “What is Test-Driven Development?

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: