【问题标题】:In Objective-C++, for testing, how can I make a class nil at runtime?在 Objective-C++ 中,为了测试,我如何在运行时创建一个类 nil?
【发布时间】:2021-06-24 21:37:24
【问题描述】:

情况如下:

在异步函数中,我捕获了一个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 并触发该委托通知?

【问题讨论】:

  • 如果你删除了对该对象的所有引用,那么该对象应该被释放,弱引用应该变为 nil。
  • 使用dispatch来延迟asyncMethod还是使用runtime来交换实现插入代码设置self为nil?
  • @childrenOurFuture 如果您发布了一个示例,我很乐意支持并接受 :)
  • 除了auto 类型推断之外,这里还有其他 C++ 吗?在我看来不像。在这种情况下,将标题从“Objective-C++”改为“Objective-C”可能会吸引更多眼球,因为 Objective-C++ 是一个非常小众的东西,回答问题的专家(嗨!)相对较少。
  • 我很困惑你为什么要这么做。如果弱自我在分配时不为零,则强自我不能为零。如果您想测试 nil 弱自我,只需测试 nil ...

标签: objective-c unit-testing objective-c-blocks objective-c++


【解决方案1】:

据我所知,你没有指定任何类名,但假设你有:

@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

在这种情况下,我会将IvarClass 子类化为StubIvarClassDelayedAsync,您可以在其中覆盖- (void) someAsyncMethod:,以便将块简单地存储在ivar 中。然后,您按照- (void)completeAsyncMethod 的行在其上实现另一个方法,该方法调用该块。

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

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

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

【讨论】:

  • 抱歉,这是我公司的产品,所以我无法举出任何不会编造名字的例子。我知道——这并不理想。你愿意写一个例子吗?解释很好,但代码往往不言自明。感谢您的写作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多