Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does instantiating a UIFont in an iphone unit test cause a crash?

I'm trying to unit test some iphone code that instantiates fonts. I've narrowed it down to the following crashing unit test:

#import "test.h"
#import <UIKit/UIKit.h>


@implementation test

- (void)testFonts {
  [UIFont systemFontOfSize:12];
}

@end

This crashes with the error:

Test Case '-[test testFonts]' started.
/Developer/Tools/RunPlatformUnitTests.include: line 415: 79768 Trace/BPT trap          "${THIN_TEST_RIG}" "${OTHER_TEST_FLAGS}" "${TEST_BUNDLE_PATH}"
/Developer/Tools/RunPlatformUnitTests.include:451: error: Test rig '/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.sdk/Developer/usr/bin/otest' exited abnormally with code 133 (it may have crashed).

It seems like there's some setup I'm not doing in my unit test target to make this work. How do you unit test things that instantiate fonts?

like image 576
Scotty Allen Avatar asked Nov 06 '09 18:11

Scotty Allen


3 Answers

One of my friends was recently running into this, and I dug out the last project I successfully set this up on. The trick is to run any of your tests that involve UIFont in application tests, rather than unit tests. Here are a few things to make sure of when setting up your application test target:

  1. BUILD PHASES: Bring your production code into your test target by including your main target as one of your test target's dependencies, rather than including the .m files in your test target. This is just for organization.
  2. BUILD SETTINGS: Make sure your test target's "Bundle Loader" is set to $(BUILT_PRODUCTS_DIR)/Your Product Name.app/Your Product Name Again. Take note, it's .../Product.app/Product - that is, there is no .app in the final segment of the path. If you're curious to see the file you're referring to, find your build product, right click, select View Package Contents, then find the executable.
  3. BUILD SETTINGS: Your test target's "Test Host" should be set to $(BUNDLE_LOADER). Easy peasy.
  4. BUILD SETTINGS: The test target's Other Linker Flags should include -framework SenTestingKit.
  5. BUILD SETTINGS: "Test After Build" should be No.
  6. SCHEME: 'Build' should include both your test target, and your main target, with "test" the only box selected in both targets.
  7. SCHEME: 'Test' should include your test target only. The files it includes will automatically be added to the list.

... hopefull this'll be enough to get you all going. It's not all cleanly documented in one place, and figuring out how to get both kinds of tests running took more time and pain than I'd like to admit.

It's strange that Apple seems to have pulled down their own doco on the matter. I wonder if there's another change coming...

Please hit me up if you have any additions to the above. It's not a complete guide to setting up Application testing, but the above are the undocumented stumbling blocks I ran into. FMI, I highly recommend this CocoaWithLove article.

like image 88
beOn Avatar answered Oct 07 '22 13:10

beOn


It doesn't state it very well, but Apple's Testing Kit splits unit tests into two separate categories:

  • Logic Tests

    These tests check the correct functionality of your code in a clean-room environment.

  • Application tests

    These tests check the functionality of your code in a running application.

There appears to be a lot of UI related code that can't be run in the "Logic Test" case. More information about Logic Tests vs Application Tests here.

http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/UnitTesting/01-Unit-Test_Overview/overview.html

like image 35
dmaclach Avatar answered Oct 07 '22 13:10

dmaclach


I'm seeing this exact problem with 3.2 (and 3.1.3). I've seen it in two separate machines, so I don't think that my SDK is broken.

I created a new iPhone view based project, and added a unit test, and one test case.

This is set up as a logic test.

Console output is as follows:

Test Case '-[TestTests testTests]' started.
/Developer/Tools/RunPlatformUnitTests.include: line 415: 21141 Trace/BPT trap               "${THIN_TEST_RIG}" "${OTHER_TEST_FLAGS}" "${TEST_BUNDLE_PATH}"
/Developer/Tools/RunPlatformUnitTests.include:451: error: Test rig  '/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.3.sdk/Deve loper/usr/bin/otest' exited abnormally with code 133 (it may have crashed).
Command /bin/sh failed with exit code 1

If I set up the unit test for debugging, then I can see the crash, with the following stacktrace:

#0  0x00342d51 in __HALT 
#1  0x002947c7 in _CFRuntimeCreateInstance
#2  0x00b8441e in GSFontCreateWithName
#3  0x028c8f31 in +[UIFont systemFontOfSize:]

I can see Kendall's point (UIKit stuff may only work on the device), but that doesn't seem to be documented very well anywhere.

like image 24
Snydely Whiplash Avatar answered Oct 07 '22 13:10

Snydely Whiplash