在 Objective-C++ 中,为了测试,我如何在运行时使 class nil?

In Objective-C++, for testing, how can I make a class nil at runtime?

情况如下:

在异步函数中,我捕获了一个 weakSelf。

__block auto weakSelf = self;

然后,在块内,我捕获了那个 weakSelf 的 strongSelf。

[_someIvar someAsyncMethod:^{
   __strong auto strongSelf = weakSelf;
}];

但是,如果 strongSelf 为 nil,我会进行一些错误处理和报告。

if (!strongSelf) {
   _NotifyDelegate(someDeallocationError); // C
}

整个事情:

__block auto weakSelf = self;
[_someIvar someAsyncMethod:^{
   __strong auto strongSelf = weakSelf;
   if (!strongSelf) {
      // How can I trigger this line?
      _NotifyDelegate(someDeallocationError); // C
   }
}
}];

这都是遗留代码,我正在使用 OCMock 添加单元测试。如何在运行时使 strongSelf 为 nil 并触发该委托通知?

据我所知,您还没有指定任何 class 名称,但假设您有:

@interface SomeClass

…

@end

…

@interface IvarClass
- (void) someAsyncMethod:(void(^)(void))block;
@end

…

@implementation SomeClass
{
    IvarClass* _someIvar;
}
…

- (void)someMethod
{
  __block auto weakSelf = self;
  [_someIvar someAsyncMethod:^{
    __strong auto strongSelf = weakSelf;
    if (!strongSelf) {
      // How can I trigger this line?
      _NotifyDelegate(someDeallocationError); // C
    }
  }];
}

@end

在这种情况下,我会用 StubIvarClassDelayedAsync 替代 class IvarClass,您可以在其中覆盖 - (void) someAsyncMethod:,这样块就简单地存储在一个 ivar 中。然后,您可以按照 - (void)completeAsyncMethod 的方式在其上实现另一个方法,该方法调用块。

您需要在测试中使用此 StubIvarClassDelayedAsync 的实例作为您的 _someIvar - 或者您可以通过 SomeClass 上现有的 API 直接注入它,否则您可能需要 subclass SomeClass 来更改创建生产实例的位置。

在测试方法中将它们放在一起:在 @autoreleasepool 块中,创建 SomeClass 的实例(或其存根子 class),用实例准备它StubIvarClassDelayedAsync,然后调用 someMethod。这反过来会导致调用 someAsyncMethod: 的重写版本,它存储块引用。 (您可以断言调用该方法是为了良好的衡量标准。)nil 输出测试中的 SomeClass 指针并关闭池块以删除任何最后的引用。您可能想要断言 dealloc 是在您的 SomeClass instance 上调用的,如果使用虚拟子 class,您可以轻松地做到这一点。但是,请确保保留指向 StubIvarClassDelayedAsync 实例的指针。最后,在该存根实例上调用 completeAsyncMethod,这应该会导致该块采用错误处理分支。

如果您提供的不仅仅是未命名的片段,我会更具体地说明代码示例,如果您在相应方法中的这些片段之前或之后有代码,那么可能需要考虑这些代码帐户或重构第一。真名也很有用。