Using OCMock 1.77 for Unit and Application Test with iOS4 and Xcode 4/SDK4.3
Asked Answered
C

2

7

I am trying to use OCMock 1.77 for unit and application testing with iOS4 and Xcode 4/SDK4.3. I have followed the instructions to do using OCMock as a static library found here: http://www.mulle-kybernetik.com/software/OCMock/. The unit and application tests run fine without OCMock.

When I add OCMock and try to run OCMock's test suite for the simulator (unit tests), my test rig crashes with code 134. The test rig runs fine for a device (application tests). If I look in the console, I see the message below -- which suggests that I haven't added the -force_load linker flag per the instructions at the above URL. But I have... Any thoughts?

I looked at this: Test rig exited abnormally with code 134 with OCMock verify on iOS 4 which suggests this behavior is a bug -- but I'm not sure it is the same situation since I am running the OCMock test suite. If it is a bug, is there a work-around to use mocks in unit testing?

TIA.

=====

Console output:

3/30/11 1:02:32 AM  otest[38552]    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '** Expected method not present; the method getArgumentAtIndexAsObject: is not implemented by NSInvocation. If you see this exception it is likely that you are using the static library version of OCMock and your project is not configured correctly to load categories from static libraries. Did you forget to add the -force_load linker flag?'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x004a05a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x002cf313 objc_exception_throw + 44
    2   CoreFoundation                      0x00458ef8 +[NSException raise:format:arguments:] + 136
    3   CoreFoundation                      0x00458e6a +[NSException raise:format:] + 58
    4   LogicTests                          0x00f89de4 +[OCMockObject initialize] + 115
    5   libobjc.A.dylib                     0x002cfd9b _class_initialize + 380
    6   libobjc.A.dylib                     0x002d773f prepareForMethodLookup + 73
    7   libobjc.A.dylib                     0x002ce069 lookUpMethod + 86
    8   libobjc.A.dylib                     0x002ce1d6 _class_lookupMethodAndLoadCache + 40
    9   libobjc.A.dylib                     0x002e10e3 objc_msgSend + 87
    10  SenTestingKit                       0x20108824 +[NSObject(SenTestRuntimeUtilities) senAllSubclasses] + 107
    11  SenTestingKit                       0x201074a7 +[SenTestSuite updateCache] + 39
    12  SenTestingKit                       0x20107443 +[SenTestSuite suiteForBundleCache] + 92
    13  SenTestingKit                       0x201073a4 +[SenTestSuite testSuiteForBundlePath:] + 108
    14  SenTestingKit                       0x2010606b +[SenTestProbe specifiedTestSuite] + 332
    15  SenTestingKit                       0x20106792 +[SenTestProbe runTests:] + 156
    16  otest                               0x000023c7 0x0 + 9159
    17  otest                               0x000025f2 0x0 + 9714
    18  otest                               0x0000209a 0x0 + 8346
    19  otest                               0x00002049 0x0 + 8265
)
Consign answered 30/3, 2011 at 6:12 Comment(0)
C
3

I can reproduce this by removing the -force_load flag. Check to make sure it's set on your test target, not your main target, and that it points to the correct location of the static library. In my case, that's

-force_load $(PROJECT_DIR)/Libraries/libOCMock.a

The other SO question you linked is just saying that when a mock's verify method fails, it throws an exception from a category method on NSInvocation, which causes otest to crash. It still works; the message is just more cryptic than an assertion failure, which XCode labels as an error in your test class.

Catarinacatarrh answered 30/3, 2011 at 15:28 Comment(16)
The flags are set correctly on the test target. The unit test target crashes before I even create a test case to run -- so it is more than just a cryptic assertion failure.Consign
I'm pretty sure this bug is causing this problem: openradar.appspot.com/8081169Consign
That bug is not the cause of the stack trace above. That bug is related to the fact that the exception can't be caught--in the context of OCMock, this means a verification failure has a less than desirable error, since OCMock can't catch the failure and wrap it.Catarinacatarrh
Your stack trace is saying that getArgumentAtIndexAsObject, a method defined on an NSInvocation category by the OCMock library, doesn't exist. That's because the category isn't being loaded from the static library. See developer.apple.com/library/mac/#qa/qa1490/_index.html. Are you sure -force_load is followed by the correct path to the static library? Try replacing it with -all_load. If that works, the path after -force_load is most likely wrong, or there's something else funky about your linker flags.Catarinacatarrh
I do appreciate you hanging in there and trying to help me chrispix. I've tried lots of different configs now. When I take my current project's state -- which runs non-OCMock unit tests and OCMock application tests fine and use these flag settings: HEADER_SEARCH_PATHS = /usr/include/libxml2 $(PROJECT_DIR)/Libraries/Headers, LIBRARY_SEARCH_PATHS = $(inherited) "$(SRCROOT)/Libraries" $(inherited) "$(PROJECT_DIR)/Libraries" and OTHER_LDFLAGS = -framework Foundation -framework SenTestingKit -framework UIKit -lxml2 -ObjC -force_load $(PROJECT_DIR)/Libraries/libOCMock.a,Consign
my test rig crashes with: Test rig '/Developer-Xcode4.0.1-SDK4.3/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/Developer/usr/bin/otest' exited abnormally with code 134 (it may have crashed).Consign
Great news! I tried your "-all_load" suggestion and it worked!Consign
Now I need to do some reading to understand the difference between the -all_load and -force_load linker flags. Thanks again chrispix!Consign
The difference between -all_load and -force_load is that -all_load tells the linker to load object files from all libraries it sees. -force_load takes an argument and tells the linker to load object files from that library. So if -all_load works but -force_load doesn't, it seems like it's not finding the library at that path. The list of flags you pasted in has a trailing comma. Is that in the flag, or is it a typo? Does the project directory have a space in it? If so, you need to quote the argument, like -force_load "$(PROJECT_DIR)/Libraries/libOCMock.a"Catarinacatarrh
You could also try the full filesystem path as a test, like -force_load /Users/Erik/myproject/Libraries/libOCMock.a.Catarinacatarrh
I added the commas for the comment. The project directory name does not have spaces (but very well could in the future) but I did not quote the argument. After fixing this, it still crashes with the -force_load switch. The test rig still crashes with I use the absolute path rather than $(PROJECT_DIR).Consign
Weird. Well, I suppose if it's in your test target, there's no harm in just using -all_loadCatarinacatarrh
Yeah, very strange. When I get some free time I'll try the -force_load on a fresh project -- maybe there's something else in my settings that is causing an issue. Thanks again.Consign
I have found that the test rig will crash per the other linked stackoverflow question/bug whenever something doesn't pass a mock test. Very annoying.Consign
Yep, it's not spectacular, but you should be getting a stack trace explaining the failure. For my workflow, it's not really a problem.Catarinacatarrh
Agreed. The stack trace does point you to the test failure, so it is just a different way of showing a test failure.Consign
L
8
  • Download OCMock *.** from http://ocmock.org/#download (At the moment of this writing 1.77)
  • unpack in a OCMock/ (or another folder) --> You will have two folder "Release" & "Source"
  • Copy the "Release/Library" folder inside your xCode project folder
  • Link your file with xcode dragging all the "Library" folder inside your porject
    • Select as the target the application TEST target!
  • Go to the "build settings" of your test target
    • Under "Search Paths" add: +"Header Search Paths" --> insert the path to your OCMock headers(.h) (something like $(PROJECT_DIR)/Library/Headers) +"Library Search Paths" --> insert the path to your OCMock library(.a) (something like $(PROJECT_DIR)/Library/) Note: as path you can also use $(PROJECT_DIR) or $(SRCROOT)/ and select the recursive checkbox to avoid insert the ocmplete path
      • Under "Linking" add: + "Other Link Flags" --> -all_load

Everything should now work correctly. To verifiy:

#import <OCMock/OCMock.h>
// simple test to ensure building, linking, 
// and running test case works in the project
- (void)testOCMockPass {
id mock = [OCMockObject mockForClass:NSString.class];
[[[mock stub] andReturn:@"mocktest"] lowercaseString];
NSString *returnValue = [mock lowercaseString];
STAssertEqualObjects(@"mocktest", returnValue, @"Should have returned the expected string.");
}

- (void)testOCMockFail {
id mock = [OCMockObject mockForClass:NSString.class];
[[[mock stub] andReturn:@"mocktest"] lowercaseString];
NSString *returnValue = [mock lowercaseString];
STAssertEqualObjects(@"thisIsTheWrongValueToCheck", returnValue, @"Should have returned the expected string."); 
}

Many thanks to:

Enrico Bottani

Lithia answered 21/9, 2011 at 9:14 Comment(0)
C
3

I can reproduce this by removing the -force_load flag. Check to make sure it's set on your test target, not your main target, and that it points to the correct location of the static library. In my case, that's

-force_load $(PROJECT_DIR)/Libraries/libOCMock.a

The other SO question you linked is just saying that when a mock's verify method fails, it throws an exception from a category method on NSInvocation, which causes otest to crash. It still works; the message is just more cryptic than an assertion failure, which XCode labels as an error in your test class.

Catarinacatarrh answered 30/3, 2011 at 15:28 Comment(16)
The flags are set correctly on the test target. The unit test target crashes before I even create a test case to run -- so it is more than just a cryptic assertion failure.Consign
I'm pretty sure this bug is causing this problem: openradar.appspot.com/8081169Consign
That bug is not the cause of the stack trace above. That bug is related to the fact that the exception can't be caught--in the context of OCMock, this means a verification failure has a less than desirable error, since OCMock can't catch the failure and wrap it.Catarinacatarrh
Your stack trace is saying that getArgumentAtIndexAsObject, a method defined on an NSInvocation category by the OCMock library, doesn't exist. That's because the category isn't being loaded from the static library. See developer.apple.com/library/mac/#qa/qa1490/_index.html. Are you sure -force_load is followed by the correct path to the static library? Try replacing it with -all_load. If that works, the path after -force_load is most likely wrong, or there's something else funky about your linker flags.Catarinacatarrh
I do appreciate you hanging in there and trying to help me chrispix. I've tried lots of different configs now. When I take my current project's state -- which runs non-OCMock unit tests and OCMock application tests fine and use these flag settings: HEADER_SEARCH_PATHS = /usr/include/libxml2 $(PROJECT_DIR)/Libraries/Headers, LIBRARY_SEARCH_PATHS = $(inherited) "$(SRCROOT)/Libraries" $(inherited) "$(PROJECT_DIR)/Libraries" and OTHER_LDFLAGS = -framework Foundation -framework SenTestingKit -framework UIKit -lxml2 -ObjC -force_load $(PROJECT_DIR)/Libraries/libOCMock.a,Consign
my test rig crashes with: Test rig '/Developer-Xcode4.0.1-SDK4.3/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/Developer/usr/bin/otest' exited abnormally with code 134 (it may have crashed).Consign
Great news! I tried your "-all_load" suggestion and it worked!Consign
Now I need to do some reading to understand the difference between the -all_load and -force_load linker flags. Thanks again chrispix!Consign
The difference between -all_load and -force_load is that -all_load tells the linker to load object files from all libraries it sees. -force_load takes an argument and tells the linker to load object files from that library. So if -all_load works but -force_load doesn't, it seems like it's not finding the library at that path. The list of flags you pasted in has a trailing comma. Is that in the flag, or is it a typo? Does the project directory have a space in it? If so, you need to quote the argument, like -force_load "$(PROJECT_DIR)/Libraries/libOCMock.a"Catarinacatarrh
You could also try the full filesystem path as a test, like -force_load /Users/Erik/myproject/Libraries/libOCMock.a.Catarinacatarrh
I added the commas for the comment. The project directory name does not have spaces (but very well could in the future) but I did not quote the argument. After fixing this, it still crashes with the -force_load switch. The test rig still crashes with I use the absolute path rather than $(PROJECT_DIR).Consign
Weird. Well, I suppose if it's in your test target, there's no harm in just using -all_loadCatarinacatarrh
Yeah, very strange. When I get some free time I'll try the -force_load on a fresh project -- maybe there's something else in my settings that is causing an issue. Thanks again.Consign
I have found that the test rig will crash per the other linked stackoverflow question/bug whenever something doesn't pass a mock test. Very annoying.Consign
Yep, it's not spectacular, but you should be getting a stack trace explaining the failure. For my workflow, it's not really a problem.Catarinacatarrh
Agreed. The stack trace does point you to the test failure, so it is just a different way of showing a test failure.Consign

© 2022 - 2024 — McMap. All rights reserved.