1

I'm trying to run unit tests from the command line but they fail while they run perfectly fine in Xcode 4.6. I can't figure out what's the cause of failure:

Here's the command I'm using:

xcodebuild -sdk iphonesimulator -project myproject.xcodeproj 
    -scheme 'MyProjectApplicationTests' 
    -configuration Debug clean build 
    RUN_UNIT_TEST_WITH_IOS_SIM=YES TEST_AFTER_BUILD=YES TEST_HOST=''

I have no usage of NSURL or to 'initFileURLWithPath' in my tests. Here's the error:

/Applications/Xcode.app/Contents/Developer/Tools/RunPlatformUnitTests.include:412: note: Started tests for architectures 'i386'
Run unit tests for architecture 'i386' (GC OFF)
/Applications/Xcode.app/Contents/Developer/Tools/RunPlatformUnitTests.include:419: note: Running tests for architecture 'i386' (GC OFF)
2013-06-04 22:09:57.605 otest[85321:707] Unknown Device Type. Using UIUserInterfaceIdiomPhone based on screen size
2013-06-04 22:09:57.624 otest[85321:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'
*** First throw call stack:
(0xa05012 0x71ce7e 0xa04deb 0x2a9b1 0x2a93b 0x4d3c5c9 0x71d7cf 0x724a0d 0x71baeb 0x71be22 0x72e0e1 0x2010879a 0x20106ef5 0x20107124 0x20107196 0x2010624c 0x201063da 0x7305c8 0x2342 0x25ef 0x268c 0x2001 0x1f71)
libc++abi.dylib: terminate called throwing an exception
/Applications/Xcode.app/Contents/Developer/Tools/RunPlatformUnitTests.include: line 415: 85321 Abort trap: 6           "${THIN_TEST_RIG}" "${OTHER_TEST_FLAGS}" "${TEST_BUNDLE_PATH}"
/Applications/Xcode.app/Contents/Developer/Tools/RunPlatformUnitTests.include:451: error: Test rig '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/Developer/usr/bin/otest' exited abnormally with code 134 (it may have crashed).

If there is a way to even print out the callstack (in English), I could maybe figure out where the error is from.

Paul Hansen
  • 153
  • 2
  • 12
  • You're trying to run application tests and not logic tests, aren't you? And you have `ios-sim` properly installed? – mAu Jun 05 '13 at 15:07
  • 1
    I have the iOS simulator app although when I type in 'ios-sim' on command line, there's nothing. Listing /Applications/Xcode.app/Contents/Applications shows that I have 'iPhone Simulator.app'. – Paul Hansen Jun 05 '13 at 15:30
  • As for the distinction of Application Tests vs Unit Tests, this is a target that was created as a Test Bundle. I'm not sure what discerns a test as a 'Logic Tests' vs 'Application Test' - the whole concept seems wonky to me. None the less, the tests all derive from SenTestCase. – Paul Hansen Jun 05 '13 at 15:34
  • As @GayleDDS said, application tests are executed as part of your application, means Xcode will need to run the simulator. Logic tests only need to execute the classes being testet. The difference can be seen in the `TEST_HOST` build configuration variable. If it's set to your application executable, the target is running application tests, if it's empty, it will run logic tests. Have a look at the following post: [Xcode 4: Run tests from the command line (xcodebuild)?](http://stackoverflow.com/a/10823483/773625). Or clear the `TEST_HOST` variable in your tests target. – mAu Jun 06 '13 at 07:14

1 Answers1

8

The issue is that xcodebuild does not natively support application tests in the simulator. To run applications tests in the simulator from the command line you need an open source utility ios-sim and a tweek to your tests target run script.

1) Install ios-sim https://github.com/phonegap/ios-sim

$ curl -L https://github.com/phonegap/ios-sim/zipball/1.9.0 -o ios-sim-1.9.0.zip
$ unzip ios-sim-1.9.0.zip 
$ cd phonegap-ios-sim-538ef1a/
$ sudo rake install prefix=/usr/local/

2) Edit your tests target run script. This script is from Atlassian's fabulous documentation. I love Atlassian makers of JIRA, Stash, Confluence, and my new best friend SourceTree. Full disclosure they acquired SourceTree and it's developer then released it for FREE.

Replace existing:

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

With this: (Source https://confluence.atlassian.com/display/BAMBOO/Xcode)

if [ "$RUN_UNIT_TEST_WITH_IOS_SIM" = "YES" ]; then
    test_bundle_path="$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.$WRAPPER_EXTENSION"
    ios-sim launch "$(dirname "$TEST_HOST")" --setenv DYLD_INSERT_LIBRARIES=/../../Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection --setenv XCInjectBundle="$test_bundle_path" --setenv XCInjectBundleInto="$TEST_HOST" --args -SenTest All "$test_bundle_path"
    echo "Finished running tests with ios-sim"
else
    "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"
fi

enter image description here

3) Run your tests

xcodebuild \
    -sdk iphonesimulator6.1 \
    -project DC\ Wire\ Sizer.xcodeproj \
    -target DC\ Wire\ Sizer\ Tests \
    -configuration Debug \
    RUN_UNIT_TEST_WITH_IOS_SIM=YES 

...

Test Suite 'All tests' finished at 2013-06-06 16:03:35 +0000.
Executed 104 tests, with 0 failures (0 unexpected) in 0.991 (1.063) seconds

Finished running tests with ios-sim
Showing first 200 notices only


** BUILD SUCCEEDED **

Useful Commands:

xcodebuild -showsdks

$ xcodebuild -showsdks
OS X SDKs:
    Mac OS X 10.7                   -sdk macosx10.7
    OS X 10.8                       -sdk macosx10.8

iOS SDKs:
    iOS 6.1                         -sdk iphoneos6.1

iOS Simulator SDKs:
    Simulator - iOS 4.3             -sdk iphonesimulator4.3
    Simulator - iOS 5.0             -sdk iphonesimulator5.0
    Simulator - iOS 5.1             -sdk iphonesimulator5.1
    Simulator - iOS 6.0             -sdk iphonesimulator6.0
    Simulator - iOS 6.1             -sdk iphonesimulator6.1

xcodebuild -list -project

$ xcodebuild -list -project DC\ Wire\ Sizer.xcodeproj
Information about project "DC Wire Sizer":
    Targets:
        DC Wire Sizer
        DC Wire Sizer Tests
        In Work Unit Test

    Build Configurations:
        Debug
        Release_AppStore
        Release_TestFlight

    If no build configuration is specified and -scheme is not passed then "Release_AppStore" is used.

    Schemes:
        DC Wire Sizer
        DC Wire Sizer - App Store
        InWorkUnitTest

Application Test vs Logic Tests
The unit test target that is created for new projects is an Application Unit Test. It injects your test code into the app by setting BUNDLE_LOADER and TEST_HOST in the build settings. The test targets you create from the New Target menu are logic tests. Logic test are stand alone independent from your application.

This is my Bundle Loader and Test Host Values.

Bundle Loader: $(BUILT_PRODUCTS_DIR)/DC Wire Sizer.app/DC Wire Sizer
Test Host:     $(BUNDLE_LOADER)

Potential issue: if you have multiple versions of Xcode installed. Then you need to check your xcode-select setting:

gdunham: ~$ xcode-select -print-path
/Applications/Xcode.app/Contents/Developer
GayleDDS
  • 4,443
  • 22
  • 23
  • I'm still running 10.8.3 and don't have any crashes of the simulator that 10.8.4 users are seeing. The test bundle was created sometime ago (not sure in which version of Xcode) - is there some way to discern if the project has Application or Logic tests? – Paul Hansen Jun 06 '13 at 01:57
  • Yes check the build settings for your test target, in the Linking section if the Bundle Loader is set. This is a Application Unit Test. – GayleDDS Jun 06 '13 at 03:47
  • @PaulHansen updated answer to also check your xcode-select setting. – GayleDDS Jun 06 '13 at 03:54
  • $ xcode-select -print-path returned: /Applications/Xcode.app/Contents/Developer – Paul Hansen Jun 06 '13 at 05:11
  • Under Linking: Bundle Loader is set to: build/[Debug|Release]-iphoneos/MyApp.app/MyApp – Paul Hansen Jun 06 '13 at 05:13
  • Under Unit Testing, Test Host is set to: build/[Debug|Release]-iphoneos/MyApp.app/MyApp – Paul Hansen Jun 06 '13 at 05:14
  • Finally caught the clue-train. Completely rewrote answer. This has been on my list of todo's for a while now. @PaulHansen Thanks buddy for helping me get my unit tests automated. – GayleDDS Jun 06 '13 at 16:53
  • Good recap. Just want to add that sometimes you get an error like " Error Domain=DTiPhoneSimulatorErrorDomain Code=2 "Simulator session timed out.". I'm running application tests within an CI environment and it helps to first run `killall iPhone\ Simulator`. – mAu Jun 07 '13 at 06:30