There are at least three very important sources of information:
- http://longweekendmobile.com/2011/04/17/xcode4-running-application-tests-from-the-command-line-in-ios/
- http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests-from-the-command-line/
- http://www.raingrove.com/2012/03/28/running-ocunit-and-specta-tests-from-command-line.html
Having said that, here some additional hints.
- It does not really matter if you use schemes with workspaces (or without workspaces) or you decide to use targets. Both will work just fine.
- iPhone Simulator will start regardless of the kind of testing you are doing. It will start with logic tests and it will start with application tests. The difference is that with logic tests it does not run your app and so you have no access to the application object. Also, the simulator window will not be brought to the foreground when running logic tests – therefore it will not be disruptive – just do not kill the simulator after each run, and then you will hardly notice its presence.
- Logic Tests are naturally supported from the command line. For Application Tests you will have to do something extra.
CLOSE YOUR iOS SIMULATOR BEFORE RUNNING THE COMMANDS BELOW!
Running Logic Tests from command line
Assuming your logic test target has name LogicUnitTests, the command to run your logic tests is:
xcodebuild -target LogicUnitTests -configuration Debug -sdk iphonesimulator5.1 TEST_AFTER_BUILD=YES clean build
The TEST_AFTER_BUILD=YES option option is only needed if you do not have Test After Build option set to Yes in the Unit Testing group in your target’s Build Settings. If you like schemes and workspaces, the same effect will be achieved with the following command:
xcodebuild -workspace MyWorkspace.xcworkspace -scheme LogicUnitTests -sdk iphonesimulator5.1 -configuration Debug TEST_AFTER_BUILD=YES clean build
Running Application Tests from command line
As mentioned above, Application Tests are not natively supported by malicious people from Apple. So to make it work in Xcode 4.3.2 you have to do the following first:
- Got to your
Applicationsfolder, locate Xcode, right click and choose Show Package Contents. - Locate the file: /Applications/Xcode.app/Contents/Developer/ Platforms/iPhoneSimulator.platform/ Developer/Tools/RunPlatformUnitTests 3. In the root of your project create folder
XcodeScriptsand copy the file located above to this folder. -
Change line
95from:Warning ${LINENO} "Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set)."to:
export OTHER_TEST_FLAGS="-RegisterForSystemEvents" RunTestsForApplication "${TEST_HOST}" "${TEST_BUNDLE_PATH}"and…save the file.
-
In your Application Tests target’s Build Phases tab, got to Run Script phase and change the command from:
"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"to:
"${PROJECT_DIR}/XcodeScripts/RunPlatformUnitTests"
After all those steps you can now run your Application Tests with the following command:
xcodebuild -target ApplicationUnitTests -configuration Debug -sdk iphonesimulator5.1 TEST_AFTER_BUILD=YES clean build
Or, if you insist on using schemes and workspaces:
xcodebuild -workspace MyWorkspace.xcworkspace -scheme ApplicationUnitTests -sdk iphonesimulator5.1 -configuration Debug TEST_AFTER_BUILD=YES clean build
What is interesting for me, and maybe it can be a positive surprise, is that the iPhone Simulator will not be started (at least without GUI). I was a bit scared that maybe my application tests are not run as logic tests, but it does not seem so. My application objects is accessible and view are perfectly constructed. The following code should not fail if your test is run as an application test:
UIApplication *application = [UIApplication sharedApplication];
STAssertNotNil(application,@"application is nil!");
AppDelegate *appDelegate = [application delegate];
STAssertNotNil(appDelegate,@"appDelegate is nil!");
UIWindow *window = [appDelegate window];
STAssertNotNil(window,@"window is nil!");
self.vc = (ViewController*)[window rootViewController];
Do not forget to adjust the view controller and the application delegate classes to the ones you use in your project.
Tags: Agile, Automation, Continuous Integration, iPhone, Test Driven Development, Unit Testing, Xcode, Xcode Application Unit Tests, Xcode Logic Unit Tests
Thanks for the post. This is an ongoing problem that I wish Apple would fix.
One thing I noticed is that often the tests fail if the simulator is already open. I ended up adding a little Applescript to my Makefile that kills the simulator immediately before running the application unit tests (logic unit tests seem fine as you say). I wrote it up http://www.stewgleadow.com/blog/2012/02/09/running-ocunit-and-kiwi-tests-on-the-command-line/
It sounds like you don’t have much love for schemes. Is there a reason for that? While fiddly, I’ve found for complex build dependencies they work a lot better than building the targets – especially from the command line. I prefer everything in the derived data directory for the workspace than in individual local build directories for each target.
You are absolutely right. Workspaces and schemes are absolutely great and I learning more and more them
. The original blog post about running tests from command line were mentioning both solutions, so I decided to follow the same path. I must sound ironic the way I am writing about schemes: that’s just me…
I will have to look at your blog, I tried Kiwi time ego, just after ARC was introduced and at that time it did not work for me. I have to retry soon.
Thanks for you comment.
With Xcode4, it doesn’t work. And neither does it work to set TEST_AFTER_BUILD as an environment variable.
/usr/bin/xcodebuild -project “XYZ.xcodeproj” -sdk “macosx10.7″ -configuration debug -target TEST_AFTER_BUILD=YES all-test
Build settings from command line:
SDKROOT = macosx10.7
xcodebuild: error: The project ‘XYZ.xcodeproj’ does not contain a target named ‘TEST_AFTER_BUILD=YES’.
make: *** [tests] Error 65
Oops, sorry, the TEST_AFTER_BUILD=YES is misplaced. When moved before -target, it works.