OCMock - 访问部分模拟对象的弱属性会导致零星崩溃

时间:2014-07-10 17:33:06

标签: ios objective-c xcode uikit ocmock

我正在使用OCMock测试从故事板中实例化的UIViewControllers。遵循最佳实践,视图控制器视图的所有IBOutlet子视图都是weak属性。当我为这些视图控制器编写测试,其中测试调用依赖于弱属性的方法时,我发现偶发的EXC_BAD_ACCESS崩溃就像我附加的那样。

每次单元测试运行都不会发生崩溃。似乎没有模式,碰撞表面是否完全随机。这种部分模拟视图控制器的设计技术也在应用程序的许多地方使用。

可能发生什么事?我在这里尝试做的事情是否存在冲突?

@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
}

崩溃:

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

1 个答案:

答案 0 :(得分:0)

此处的问题必须与OCMock在创建partialMock时所执行的操作相关联。您可以查看源代码here

你的ViewController的视图很可能被填满了,并且随之而来的是它的所有子视图(设置为出口)

但这很重要:通常你会模拟其他对象,而不是你正在测试的系统。如果你在嘲笑你的SUT,那么你可能需要重构你的代码。

话虽如此,我使用部分模拟来模拟SUT,例如从懒惰实例化的属性返回模拟对象,并且完全正常。