This is a quick introduction to unit testing with XCode. This article does not provide a conceptual overview to unit testing.
As a first step. I did the following:
- Go to the project browser and select [ add > new file ]
- Select ‘objective c test case class’
- The file that opens immediately seems to contain a couple of tests. That, and a link to an overview document graciously provided by Apple.
- So I click, and read everything patiently (well, I’m planning to. I can display a lot of patience at times) (1).
One thing worth mentioning is that, up to stage 4 and notwithstanding footnote (1), this is a perfect introduction to unit testing, and a perfect approach to documentation. The IDE provides the way to get us started with what we want to do. The code hyperlinks the documentation.
Setting up a target for unit testing
Now to the point, what we want is write a test suite and, minimally (assuming we don’t have continuous integration, yet) wire it to the main project, so the test suite runs whenever we build.
- We need a target to run the test suite. Go to [ project > New Target > Unit Test Bundle ].
- Make a group to hold your test classes (Optional. We might as well dump everything, everywhere).
- At this point I deleted my first test class and re-created it. That’s because we need to add the test class to the test target (NOT to the main target, so uncheck that when going through the wizard) and the easy-clicky way is via the wizard, when we create a new test class.
- Switch the active target to Test (or whatever your test target is named) and target the simulator (otherwise tests will skip).
- Press build.
- Press [Build]. If you haven’t modified the sample test class, this should run OK.
- Now modify the test class to fail a test, and press ‘Build’. This should then fail the build. If you check build errors and keep unfolding, you’ll eventually find a reference to your failed test, along with whatever you set the assert to output when the test fails.
OK, this didn’t work for me at first. In the sample test class, reassign USE_APPLICATION_UNIT_TEST to zero. USE_APPLICATION_UNIT_TEST doesn’t seem to be for unit tests; this is for tests that require your application (or some other GUI, not sure… ) to be running while you test.
NOTE: I have somehow gotten into the habit of stripping #import <Foundation/Foundation.h> off my .h files. Well. If you’re doing this, you’ll get errors when trying to compile your project classes to the test target. You need to add the project’s precompiled header (*.pch) to the build configuration for the test target (see below).
Running tests every time you build the main project
Now, this is trivial and elegant at once. To ensure we pass the tests before even thinking about running our app, all we need to do is drag the test target inside the main target.
Next time we build (targeting the simulator) test classes compile and run before actually running our app. If the tests fail, nothing runs until we fix the tests :)
There are three practical issues that tend to occur when trying to put legacy code under unit test with XCode. In whatever case this results in stupidly broken builds.
- Most of your existing source files are missing from the Test target.
=> expand the main target for your project; expand the test target; now select Compile Sources in your main target. select all files in the Compile Sources group (do it from the top right panel) and drag them into Compile Sources in the test target.
- Frameworks in use are missing from the test target.
=> use the same approach as in (1). This time, duplicate content from Link Binary with Libraries.
- The precompiled header (.pch file) isn’t applied to the test target.
- Right click on the main target and choose ‘get info’.
- Select the build tab.
- Under Configuration: (top left) pick All Configurations
- Scroll down until you find the ‘Prefix header’ entry in the ‘GCC 2.2 – Language’ section. Copy the pch path/name and duplicate it to your Test target settings.
(1) At this stage, not everything being as perfect as it ought to be, I bothered popping a mail window and sending the link to myself. I wished I had an iPad icon on my desktop and could just drag the safari window to it – or the link. Yea. Kiss the future.