为什么我的对象的弱委托属性在我的单元测试中为零?

时间:2011-12-30 00:45:50

标签: objective-c ios unit-testing automatic-ref-counting

我有一个非常简单的单元测试设置。我有一个具有委托属性的类:

@interface MyClass : NSObject
...
@property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
@end

我在测试中设置了委托:

- (void)testMyMethod_WithDelegate {
  id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
  [[delegate expect] someMethod];
  myClassIvar.connectionDelegate = delegate;
  [myClass someOtherMethod];
  STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}

但是代理实际上并没有设置在我的单元测试的第3行,所以#someMethod永远不会被调用。当我将其更改为

myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, @"delegate should not be nil");

它失败了。我使用ARC,所以我的预感是弱房产被解除分配。当然,将其更改为strong会使STAssertNotNil通过。但我不想与代表那样做,而且我不明白为什么这会有所作为。根据我的阅读,ARC中的所有本地参考都是strongSTAssertNotNil(delegate)通过。当局部变量中的同一对象不是时,为什么我的弱委托属性为nil?

4 个答案:

答案 0 :(得分:8)

这是iOS运行时中的一个错误。以下讨论有更多细节。简而言之,iOS ARC运行时似乎无法处理对代理的弱引用。 OSX运行时可以。

http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252

据我所知,从讨论中已经向Apple提交了一份错误报告。如果有人对解决方法有明智的想法......

答案 1 :(得分:4)

我真的不知道这里发生了什么,但是OCMock从mockForProtocol:方法返回一个自动释放的NSProxy - 后代,我认为是正确的。也许ARC有NSProxies的问题?无论如何,我通过声明变量__weak

来克服这个问题
- (void)testMyMethod_WithDelegate {
  // maybe you'll also need this modifier inside the helper
  __weak id delegate = mockDelegateHelper(); 
  ...

在这种情况下,它确实不需要是__strong(默认值),因为它是自动释放的,而且你不会保留它......

答案 2 :(得分:2)

解决方法是使用Partial Mocks。

@interface TestMyDelegateProtocolDelegate : NSObject <MyDelegateProtocol>
@end

@implementation TestMyDelegateProtocolDelegate
- (void)someMethod {}
@end


@implementation SomeTest {
- (void)testMyMethod_WithDelegate {
  id<MyDelegateProtocol> delegate = [[TestMyDelegateProtocolDelegate] alloc] init];
  id delegateMock = [OCMockObject partialMockForObject:delegate]
  [[[delegateMock expect] someMethod]
  myClassIvar.connectionDelegate = delegate;
  [myClass someOtherMethod];
  STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}
@end

答案 3 :(得分:1)

我不是ARC专家,但我的猜测是mockDelegateHelper()正在返回一个弱对象。因此,delegate在第二行代码执行之前为零。我冒昧地猜测,mockDelegateHelper()是罪魁祸首,或者OCMock正在阻碍它操纵和创建对象的方式。