I'm using OCMock to test UIViewControllers that are instantiated from a storyboard. Following best practice, all IBOutlets of subviews of the view controller's view are weak
properties. When I'm writing tests for these view controllers in which the tests call methods that rely on the weak properties, I'm seeing sporadic EXC_BAD_ACCESS crashes like the one I attached.
The crash does not happen every unit test run. There does not seem to be a pattern, it's totally random whether the crash surfaces or not. This design technique of partially mocking the view controller is used in many places in the app as well.
What could be going on? Is there a conflict in what I'm trying to do here?
@interface CustomUIViewControllerTests : XCTestCase
@property (nonatomic, strong) CustomUIViewController *vc;
@property (nonatomic, strong) UIStoryboard *mainStoryboard;
@end
@implementation CustomUIViewControllerTests
- (void)setUp
{
[super setUp];
// In order to test data on the Storyboard - need to instantiate the Storyboard
self.mainStoryboard = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary
objectForKey:@"UIMainStoryboardFile"]
bundle:[NSBundle mainBundle]];
self.vc = [_mainStoryboard instantiateViewControllerWithIdentifier:kStoryboardVCID];
[self.vc loadView];
}
- (void)testSomething
{
id mockController = [OCMockObject partialMockForObject:self.vc];
[mockController doSomethingThatUsesAWeakProperty];
//other verification/assertions here
}
The Crash:
Process: XXXX [33756]
Path: /Users/USER/Library/Application Support/iPhone Simulator/*/XXXX.app/XXXX
Identifier: XXXX
Version: 0
Code Type: X86-64 (Native)
Parent Process: launchd_sim [33727]
Responsible: launchd_sim [33727]
User ID: 501
Date/Time: 2014-07-10 11:51:51.692 -0400
OS Version: Mac OS X 10.9.3 (13D65)
Report Version: 11
Anonymous UUID: 8B81673C-B92D-28D3-9940-47C83C140C8E
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x000000011ab0e360
External Modification Warnings:
Debugger attached to process.
VM Regions Near 0x11ab0e360:
MALLOC_TINY 0000000114700000-0000000114800000 [ 1024K] rw-/rwx SM=PRV
-->
JS JIT generated code 0000056193e99000-0000056193e9a000 [ 4K] ---/rwx SM=NUL
Application Specific Information:
iPhone Simulator 463.9.41, iPhone OS 7.1 (iPhone Retina (4-inch 64-bit)/11D167)
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x0000000103156292 __kill + 10
1 XXXX 0x000000010010f565 CLSSignalHandler + 218 (CLSSignal.m:305)
2 libsystem_platform.dylib 0x00000001030295aa _sigtramp + 26
3 Foundation 0x0000000102174225 -[NSConcreteValue getValue:] + 29
4 Foundation 0x00000001021af5be -[NSValue nonretainedObjectValue] + 25
5 XXXX 0x0000000100153e00 +[OCPartialMockObject existingPartialMockForObject:] + 160 (OCPartialMockObject.m:50)
6 XXXX 0x00000001001546e1 -[OCPartialMockObject forwardingTargetForSelectorForRealObject:] + 65 (OCPartialMockObject.m:170)
7 CoreFoundation 0x0000000102a8ba5c ___forwarding___ + 156
8 CoreFoundation 0x0000000102a8b938 _CF_forwarding_prep_0 + 120
9 XXXX 0x0000000100028ea6 -[CustomUIViewController doSomethingThatUsesAWeakProperty] + 454 (CustomUIViewControllerTests.m:121)
10 CoreFoundation 0x0000000102a8ff1c __invoking___ + 140
11 CoreFoundation 0x0000000102a8fdc4 -[NSInvocation invoke] + 308
12 CoreFoundation 0x0000000102a8ff86 -[NSInvocation invokeWithTarget:] + 54
13 XXXX 0x0000000100154999 -[OCPartialMockObject handleUnRecordedInvocation:] + 73 (OCPartialMockObject.m:217)
14 XXXX 0x0000000100151fe6 -[OCMockObject forwardInvocation:] + 102 (OCMockObject.m:190)
15 CoreFoundation 0x0000000102a8bb85 ___forwarding___ + 453
16 CoreFoundation 0x0000000102a8b938 _CF_forwarding_prep_0 + 120
17 XXXXTests 0x000000010c0d289d -[CustomUIViewControllerTests testSomething] + 573 (CustomUIViewControllerTests.m:996)
18 CoreFoundation 0x0000000102a8ff1c __invoking___ + 140
19 CoreFoundation 0x0000000102a8fdc4 -[NSInvocation invoke] + 308
20 XCTest 0x0000000109ba4c40 -[XCTestCase invokeTest] + 161
21 XCTest 0x0000000109ba4d2c -[XCTestCase performTest:] + 91
22 XCTest 0x0000000109ba5a75 -[XCTest run] + 65
23 XCTest 0x0000000109ba44df -[XCTestSuite performTest:] + 125
24 XCTest 0x0000000109ba5a75 -[XCTest run] + 65
25 XCTest 0x0000000109ba44df -[XCTestSuite performTest:] + 125
26 XCTest 0x0000000109ba5a75 -[XCTest run] + 65
27 XCTest 0x0000000109ba44df -[XCTestSuite performTest:] + 125
28 XCTest 0x0000000109ba5a75 -[XCTest run] + 65
29 XCTest 0x0000000109ba71b4 +[XCTestProbe runTests:] + 138
30 Foundation 0x00000001021846dc __NSFireDelayedPerform + 354
31 CoreFoundation 0x0000000102a5cc34 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
32 CoreFoundation 0x0000000102a5c7b2 __CFRunLoopDoTimer + 962
33 CoreFoundation 0x0000000102a457be __CFRunLoopRun + 1614
34 CoreFoundation 0x0000000102a44d83 CFRunLoopRunSpecific + 467
35 GraphicsServices 0x00000001039dcf04 GSEventRunModal + 161
36 UIKit 0x00000001010cce33 UIApplicationMain + 1010
37 XXXX 0x000000010007b889 main + 169 (main.m:16)
38 libdyld.dylib 0x000000010301f5fd start + 1