iOS test driven development can still be the topic of heated debates in the developer community. Since adopting TDD I have wanted to share my experiences within the context of iOS development. It’s a large topic so I’ve split up my thoughts into multiple parts. This first article is all about why tests are important and the golden question: “why write tests before the production code?”.
Code backed by tests allows code to be safely refactored and maintained at little cost. Writing tests after the production code can mean writing the production code, writing tests and then refactoring the production code. Writing tests before the production code gives you full coverage and is much quicker.
A conversation about iOS test driven development
Put TDD to the back of your mind for a moment. Let’s just talk about unit tests in general.
Why write unit tests in the first place?
Sure it gives you confidence about the code you’re writing but the long term benefits are much more valuable. Tests empower the developer.
Erm… empower how exactly?
Well, I am about to take over a project developed by a 3rd party on a budget. Safe to say there are very few tests and it suffers from all the common afflictions such as Massive View Controller, weird unreadable code, blocks inside blocks inside blocks – you know the deal. Anyway, in this project I found a method which was 200 lines long (I think 200 lines is too many for a class let alone a method!).
How did it get into this state?
The fear of refactoring a huge chunk of code. This method wouldn’t have started off as a 200 line method (I hope). It would have had a single purpose and you would have been able to understand exactly what it did just by reading the method signature. As time passed it would have been enhanced and changed several times; probably by several different developers.
Why didn’t these developers refactor the method as they went along?
Refactoring code is dangerous. What if you make a mistake? Who knows how that would affect other parts of the app? And refactoring code like this can be tricky. Often this sort of code is simply too complex to understand right away. Untangling this mess can lead to unexpected behaviour if you’re lucky or even crashes if not.
So how do unit tests help us?
Unit tests remove the fear; they are our safety net. If we change the production code, the tests fail. Suddenly we can refactor without worrying about the repercussions and can sleep easy knowing that we code still works.
We shouldn’t be ashamed of this safety net. It’s so easy to make simple mistakes as a developer; after all, our job can be pretty intense.
Yeah, I’ve heard it all before. Unit tests == better code. But why write tests before the production code?
Take the previous example of the 200 line method. We tend to call this kind of code ‘legacy code’ and for good reason. Imagine we need to write tests to support this code. We want to make sure it does exactly what we expect. Where do you start? The chances are that this method is not testable at all. It likely contains lots of dependencies which aren’t accessible outside the method.
So how would you write tests for this method?
You would have to refactor the code.
Isn’t that a little bit like writing the code twice?
Yup. Writing tests before production code is faster for that very reason. Sure it can feel unintuitive at first but don’t you remember the first time you learned how to code? How did you get better? The chances are it was good old fashioned hard work and practice.
How long did it take for you to pickup iOS test driven development?
I have to admit it took a couple of tries to make it stick. I didn’t quite understand the full value of full unit test coverage and my understanding of TDD was simply “writing tests first”. Whilst this is one of the rules, it isn’t very easy to learn TDD when this is your only reasoning. Now I understand (and dare I say it) enjoy TDD. In fact, I don’t think I could go back and I’ll tell you why in the next post.