Update: UIAlertView is deprecated. Check out how to test UIAlertControllers.
People assume you can’t write unit tests for user interface code. That just ain’t so. I’ve already shown you how to do UIViewController TDD. Can we do the same for UIAlertView and UIActionSheet? Sure!
This time instead of a screencast, I’ve put my code on GitHub, because you’ll want to incorporate some classes into your tests. Go to my iOSAlertViewActionSheetUnitTesting repository.
The basic trick to writing unit tests of UI code is to recognize that we don’t manage the UI ourselves. Cocoa Touch takes care of that. All we have to do is make sure we’re setting things up correctly for Cocoa Touch, and trust it to do its work. …Do you see the distinction? We don’t need to test Apple’s code, just our code. (This also keeps our tests fast.)
We do need to introduce a seam — that is, a boundary that will allow us to substitute real code with test-specific code. The real code we want to replace is directly invoking UIAlertView or UIActionSheet. Normally, you’d show an alert with code like this:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; [alertView show];
Instead of directly allocating a UIAlertView, what if we allow tests to say, “Don’t make a UIAlertView. Instead, make this mock object. It will record everything I do to it, so I can check all initializer arguments, and make sure
show was messaged.”
That’s where JMRMockAlertView and JMRMockActionSheet come in. The repository has an example project showing how to inject them, and how to use the corresponding objects JMRMockAlertViewVerifier and JMRMockActionSheetVerifier to query what happened.
For the sample tests, I put all the assertions together so you can see them all grouped together. But in practice, I break things into separate tests for:
- Alert should be shown once. Or, the action sheet should be shown once, from a particular view.
- (Any negative tests, “An alert should not be shown,” or “An action sheet should not be shown.”)
- Message text
- Button text
- What the delegate is
Once you’ve established the delegate, then you can write additional tests that directly invoke the delegate methods you want, simulating different button taps.
Oh, and don’t just copy my end result. Use the “TDD waltz” to build it up gradually, one test at a time. You can see a good order by reading my tests top-down.
Do you have any questions? Leave a comment below.