By no means is TDD (Test Driven Development) a new concept; I’ve known about it for years. I had sone some unit testing on projects prior, they became an integral part of routine when I started consulting for HP’s Software R&D lab. We’ve been very good about testing out all the important logic of the application, save automated functional testing of the UI (more on that in another post).
This post is really about TDD, not convincing you to unit test your code (something you should be doing). Actually, I’m not a diehard TDD fanatic. Rather I use principles of testing first before writing application logic. I don’t want to get stuck the pedantics of true TDD development.
My journey, if you will, started as I had a turning point in two projects for Pivotal Action that convinced me. The first project involved a bit of interplay between iBeacons (CLBeacon) and networking, which would be impractical to manually test with physical hardware. The second project involves a lot of transformations being applied to objects, and some networking. In both cases, relying on rather extensive unit tests could ensure I wasn’t breaking functionality with new features.
My general approach involves a few simple practices:
- Create a mock data set for input. I often use JSON files because it’s easily readable, and you can use the same data on multiple tests if you need. Also helpful if you’re testing mock network response data
- Create a test data set, or scenario. First pass, go with the “golden path” – the best case scenario
- Determine what your desired outcomes are in a best-case scenario
- Create separate test cases for each kind of data you may have to deal with. Again – start with the best case scenario
- Write some logic code to either transform data, or respond to it
- Go back to step 1 and create a new set of data representing one type of problem, or family of very similar problems. This could be malformed data, error codes from API services, etc. as well as common problems : out-of-bounds errors, off by one, nil, and others.
- Keep repeating 2-5 until you’ve exhausted just about every scenario you can reasonably think of.
This may seem boring and repetitive, but I assure you that thoroughly testing your logic will uncover holes in your implementation before you even start writing application and UI code. You’re also more likely to survive refactoring unscathed if you have extensive unit tests covering the changing code. I recently benefitted from this when I converted a set of model classes over to a CoreData stack. It wasn’t a perfect 1:1 refactor, but it uncovered some places where I had to adapt my expectations and logic so that the transformations would be the same in the end.
I’m not perfect at this, but I can say that doing unit testing before really getting into the guts of an application has saved me a lot of work farther down the road. I also have more confidence that changes I make aren’t breaking existing functionality. Give it a shot.