Now that I’m starting a new iOS development project, I’m trying to have close-to-complete test coverage of critical parts of my code. I’m using XCTest pretty extensively, and found that I needed to test a rather complicated private method that is critical to my app’s user experience. This post shows you how I did it.
Before we get started, I know that some people feel very strongly about testing private methods. I don’t want to get into that discussion. I just know that there is one private method that I need to test thoroughly. It’s pretty simple, really.
The first thing I did was go to my project settings. I duplicated the
Debug configuration by clicking on that ‘+’ and called the new configuration
Then I edited my schemes and for the
Test action I directed XCode to use the newly-created
Unit Testing scheme:
Then I went back to my project and added a
TESTING=1 preprocessor directive for the
Since I use CocoaPods, I had to create a
UnitTesting configuration for the
Pods project as well. I didn’t need to modify schemes any further or add any preprocessor directives for CocoaPods.
With this in place, I was able to use preprocessor directives to make my private methods public (only when testing) in my
.h (interface) file:
#ifdef TESTING -(void) myPrivateMethod; #endif
UPDATE 2014/08/12 08:34
Earlier this morning I mentioned this post to Brad Heintz, whose talk on automated unit testing I attended at the recent CocoaConf in Columbus. Brad suggested an even simpler solution, which I present here with his permission:
Declare a local category for the class under test in your test case file. Inside that category, you can re-declare the private methods so that your test case can see them. BUT: When you find yourself wanting to do that, you should step back & consider whether you’re testing behavior (which is good) or implementation.
Since the method I’m testing generates
CGPoints that are fed to a UIView’s
drawRect, I feel justified violating that rule of thumb this one time. It’s a lot easier to test this critical method when I have an array of points than when all I have is a UIView.