At this moment, if you search on Google for “unit testing ios,” the second result points to a page on Apple’s developer site that is outdated and now points to a generic “Tools Workflow Guide.” Most of the first page of results are really brief overviews on the topic or dated. Coming from Rails world, perhaps I was spoiled by the abundance of mature frameworks with tons of examples, tutorials, documentations, and even whole books on the topic. As much as I really enjoyed diving into the world of iOS development, I was very disappointed by the dearth of tools/documentations available on this front. I’m just starting to cover new code I’m writing with tests.
I’m writing this in May of 2012 so using Xcode 4.3. Apparently, until 4, the built in tools kinda sucked so GHUnit was pretty popular. As of Xcode 4, OCUnit is a very reasonable tool to use. Combined with OCMock, pretty easy to setup, easy to use, and good enough for me for now. These tests are compiled and there’s no system environment to load so they run fairly fast. I miss being able to have tests run automatically when I changed tests or code. I also miss being able to run specific tests. I’ve read somewhere that some consider this behavior a feature. Meaning that it’s best to always run all your tests. I’m not sure I buy this, but I don’t really care as long as they run fast.
It looks like there are some other functional/integration testing tools they seem a bit immature to me still. For now I’m just going to be sticking with built-in tools, a.k.a. using Instruments/Automation to record user testing scripts. This basically requires a functioning app to create these tests though. So I think the workflow for me will be to write unit/functional tests in OCUnit, implement the feature, then write integration tests in Instruments/Automation. I’m not religious about TDD but I did appreciate that it really got me write more tests. As with most people, I find it hard to get excited about writing tests for features already implemented. As much as I believe in the ability of these tests in reducing the overall implementation time, for me, the best incentive is to make the process of writing tests more enjoyable for myself.
The app I’m primarily working on now had zero test coverage before I started. It was apparently bit of a rush to implement features until now, the codebase was a rather hacky around the edges, no model layer to speak of (not using Core Data, basically no separate model code, and not syncing information with a backend). Largely due to not using Core Data in the first place, the app tended to use idiosyncratic ways of doing things in favor of idioms/apis/sample code that Apple lays out in its documentation. The scariest part was that the app was interconnected to other parts of the codebase in ways that made the app brittle to change. By far the thing that would have help on-boarding on to this app that much easier would have been to have some tests to run while I was getting familiar with the codebase. It’s hard inheriting then refactoring/adding features to a codebase you haven’t written, but to do it without any sense for how your changes are affecting the rest of the codebase is pretty nerve-wracking. I don’t think this benefit of writing tests for your code is covered enough. Having reasonable coverage helps when you have a team of people working on something, and especially when you add to the team after foundations have been laid out.