如何用模拟和预定义的答案替换异步调用?

Posted

技术标签:

【中文标题】如何用模拟和预定义的答案替换异步调用?【英文标题】:How to replace async calls with mocks and predefined answers? 【发布时间】:2013-06-01 17:42:14 【问题描述】:

我有一个简单的类来执行网络的东西。它是一个单例,它在其中封装了NSOperationQueue。当类的用户调用某种方法从网络获取数据时,该类创建从NSOperation 继承的操作类的适当实例,并设置它并添加到执行队列中。显然,这种执行是在分离的线程中异步进行的。从网络NSOperation 获取数据后,继承对象通知我的网络类,并通知感兴趣的委托有关数据完成或错误。

问题是,如何进行单元测试来检查网络类的逻辑?另外,我实际上并不想测试服务器端的行为。我只想用模拟和预定义的答案替换对服务器的实际异步调用,以测试处理程序的行为。我想检查我的课程是如何工作的,而不是服务器端。我理解测试这类东西的常见逻辑,但我对使用 OCMock 有点困惑。 最佳答案将是代码示例。我在我的项目中使用 OCUnit 和 OCMock 进行单元测试。

此外,任何文章或 github 链接都是完美的。

【问题讨论】:

【参考方案1】:

如果所有异步调用都通过您类中的内部方法,您可以简单地在您的对象上创建一个部分模拟并在该方法上使用存根/预期。然后,您可以正常调用公共方法并使用模拟来验证是否调用了内部方法。使用部分模拟会阻止调用真正的实现,因此不会发生网络活动。

至于另一半,来自异步操作的回调,只需调用将直接从您的测试中调用的方法,然后通过使用 OCUnit 断言检查其状态来检查您的类是否做正确的事情,或者,如果它反过来使用回调,则使用另一个模拟。

【讨论】:

【参考方案2】:

所以我知道这是关于 OCMock...但我想我应该把它放在那里,我用 Kiwi 成功地做到了这一点,它看起来像这样。

it(@"should refresh the client's temporary API key if it is stale before sending the request", ^
    ISLDataServiceAdd *addRequest = [ISLDataServiceAdd withRecord:@ISLFieldContact_FirstName: @"Jason" table:ISLTableContact];

    [[clientMock shouldEventually] receive:@selector(apiKey) andReturn:VALID_API_KEY];
    [[clientMock shouldEventually] receive:@selector(hasTemporaryAPIKey) andReturn:theValue(YES)];
    [[clientMock shouldEventually] receive:@selector(isTemporaryAPIKeyStale) andReturn:theValue(YES)];
    [[clientMock shouldEventually] receive:@selector(refreshTemporaryAPIKeyAndWait:)];

    [addRequest sendRequestUsingClient:clientMock completion:nil failure:nil];
);

sendRequestUsingClient:completion:failure: 是一个异步调用,因此通过将shouldEventually 与 Kiwi 一起使用,它知道在调用这些选择器之前需要等待一段时间(默认为 1 秒)。

【讨论】:

克里斯,谢谢你的回答。目前我正在共同研究 ios 的单元测试,并且发现这个任务太大了))。我目前没有使用 Kiwi,但我可能会在功能中使用它。目前我已经找到了解决我的问题的方法。我只是直接调用我需要的方法,而不需要任何方法替换或类似的东西。无论如何,非常感谢您的帮助,也许您的回答将来会对我有所帮助。或者对其他人有帮助。

以上是关于如何用模拟和预定义的答案替换异步调用?的主要内容,如果未能解决你的问题,请参考以下文章

Day834.Dubbo如何用管程实现异步转同步 -Java 并发编程实战

来自 void 类的模拟异步调用

Python爬虫编程思想(89):如何用逆向工程分析异步加载页面

Python爬虫编程思想(89):如何用逆向工程分析异步加载页面

如何处理异步 axios api 调用

SpringBoot之@Async异步调用