Whenever you are writing code that is intended for reuse it is important that the API is well documented. This will make it a lot easier for other developers to understand and integrate your code. On top of this it will also make it a lot easier to reuse that code when you need to use it yourself 6 or 12 months down the road.
In this tutorial I will use ILGeoNames as an example for how you can easily generate documentation for your own projects.
I will use the appledoc tool provided by Gentle Bytes. The
appledoc tool provides a lot of nice features including the ability to generate Apple-like html documentation as well as the ability to generate and install fully indexed and browsable Xcode documentation sets.
In this post I’ll show how to use GCOV and CoverStory to ensure that you are actually testing all parts of your code. Or at least obtain knowledge about which parts of your code that are being tested and which parts that are not being tested by your unit tests.
Having a high degree of code coverage in your unit tests helps to ensure that your code will continue working as expected even after you change parts of it, e.g. when fixing bugs, re-factoring it, adding new features, etc.
The coverage data can also be used to show when you have added enough tests to your code. Once you have obtained full test coverage of a certain function, adding more tests for that same function will probably not help you find more bugs in the code. Instead you can now focus your efforts on adding new functionality without having to worry about it breaking behind your back.
In the previous post I presented one way of implementing unit tests for iOS code that access the internet asynchronously. In this post I’ll go through how to use Mock Objects to further stabilize and optimize these tests. If you’re unfamiliar with the concept of Mock Objects I’ll suggest you first read A Brief History of Mock Objects or this Wikipedia article.
As mentioned in the previous post, it is possible that the unit tests may fail due to some outside factor even though our code is working perfectly. This could for instance be an internet service that is temporarily down or malfunctioning, or it could be your own ISP that have some problems.
By replacing the code that access the internet by Mock Objects that mimic the same behavior the unit tests can be made completely independent of external factors. Additionally by mocking the internet access the unit tests will also execute substantially faster . A speed increment by a factor 1000 or more is not unusual.
In Test Driven Development the complete Unit Test suite should ideally be executed as part of your normal compile setup. This means that execution times in the order of seconds for just a single test is an absolutely no-go. As Noel Llopis states in this blog post, the total execution time for the full test suite of your entire project should be less than 2 seconds. Whether the limit is 1, 2 or maybe even 3 seconds is not important, but the point is that it should be so fast that it doesn’t contribute to the perceived build time.
In this post I’ll go through one way of adding unit tests to code that fetch data from the internet through asynchronous threaded callbacks. As an example I’ll use the ILGeoNames library described in the previous post. More specifically I’ll show how to write unit tests for
findNearbyPlaceNameForLatitude:longitude: in the
We’re faced with three problems that prevent the normal straight-forward methods for writing unit tests:
- Asynchronous code – the result is passed back by the use of a delegate method.
- Threaded execution – the code under test is spawning off a new worker thread.
- Network access – the result is fetched from a remote internet server.
The asynchronous code and threaded execution prevents the use of a normal linear flow in the unit test code and the network access adds a lot of uncertainty and latency to the tests. We want our unit tests to be fast and stable and not fail just because some remote server or internet provider have a problem from time to time.
Fortunately there are a few fairly straight forward solutions to these problems.
Since iOS 3.0 it has been very easy for iPhone App developers to provide users with detailed information about their current location by using the built-in MKReverseGeocoder class. The MKReverseGeocoder class acts as an Objective C wrapper around Googles geocoding services and handles all the network activities as well as decoding of the returned result.
This all sounds very nice, except that you are only allowed to use the MKReverseGeocoder class if you also display the result in conjunction with a Google map. This may be perfectly fine for most Apps needing reverse geocoding but will effectively prevent other types of Apps from using this service. MyAlmanac is one of those Apps that fall into the latter category.