Kasper Munck

Building Projects and Running Tests with Xctool

Facebook recently released xctool, a tool intended to replace Apple's xcodebuild (technically, it's a wrapper), which is the command line tool for building iOS and OS X projects.

xctool is a replacement for Apple's xcodebuild that makes it easier to build and test iOS and Mac products. It's especially helpful for continuous integration.

Xctool simplifies the process of building application unit tests (and a wide variety of other tasks!) from the command line significantly. Recently I wrote about How To Run Application Unit Tests with Travis-CI, addressing the issue with running application unit tests from the command line. It turned out that additional effort is required to be able to run application unit tests from the command line. This is now past.

To demonstrate how easy xctool is to use, we'll create a dummy sample app, MyApp, with a unit test target. We'll then both build the project and run it's test cases via xctool. Compared to the previous required effort (especially when using Jenkins/Hudson), it is surprisingly simple.

MyApp

Create a new Xcode project, MyApp, of type Single View Application and check Include Unit Tests.

New Project

Then add a new scheme, MyAppTests, for the unit test target (whose name is most likely to be MyAppTests as well).

New Project

xctool doesn't support building targets using -target as xcodebuild does, hence the need of schemes. It encourages you to indicate a scheme to build and then specify a desired target with the -only flag (and further details such as a certain test class and even a specific test case).

xctool

Clone the source from Github into the root of MyApp project (the folder containing MyApp.xcodeproj). Then run:

xctool/xctool.sh -project MyApp.xcodeproj -scheme MyApp build

No additional setup is required. You can build and run tests, build the test target and run it against multiple SDK's, build the project or a workspace and a whole lot of other convenient things. To run the tests (that is, the unimplemented dummy test that's added by default), run:

xctool/xctool.sh -project MyApp.xcodeproj -scheme MyAppTests test

This runs all tests in MyAppTests in the simulator - including both logic- and application unit tests - without any problems. It's really that simple. I made a test project to check it's compatibility with Travis-CI, and (after a minor fix) it works very well, too.

Disable Unit Test Runner

The unit test target Xcode creates when checking Include Unit Tests runs a build script named RunUnitTests. When inspecting the output from xctool, you will notice this message:

/Applications/Xcode.app/Contents/Developer/Tools/RunUnitTests:68: note: RunUnitTests exited without running tests because TEST_AFTER_BUILD was set to NO.

Although this does no harm at all, warnings should never be present. Click on MyApp project in Project Navigator and select MyAppTests target. Under Build Phases -> Run Script it says:

# Run the unit tests in this test bundle.
"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"

Since building of the project is now relying 100% on xctool, it is safe to remove this build script. Run the tests again and the message is no longer showing.

Build Errors

I experienced two errors when building MyApp project with the following command:

xctool/xctool.sh -project MyApp.xcodeproj -scheme MyApp build

The first was a code signing error:

Code Sign error: A valid provisioning profile matching the application's Identifier 'dk.muncken.MyApp' could not be found

You get rid of this either by signing the project properly or specifying the SDK to be the iphonesimulator (add -sdk iphonesimulator) and thereby omit code signing.

The second was an architecture error:

No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s).

To get rid of this one, go to project settings and then under Architectures, change Build Active Architecture Only to NO.

[ xctest xcodebuild unit tests command line travis-ci ]