objective-c - 你应该如何在 Objective C/Cocoa 中模拟你不拥有的类? (例如 NSDate)

标签 objective-c mocking

规则是这样说的

Only mock objects that you own.

我想我理解这样做的原因 - 框架提供的模拟类可能会导致奇怪的行为。

还有什么选择?

当您需要使用 NSDate 的虚拟日期时怎么办?

在过去,我将日期方法从 NSDate 调换到我自己的类 - NSDateMock - 但有些东西告诉我那真的是错误的!

一个解决方案 - 一个包装器?

创建一个 NSDate 的包装器,但是你必须实现它的所有方法。

或者您会只实现您正在使用的那些吗?这似乎是一种困惑的方式。

我的问题

模拟不属于您的类(例如 NSDate)的好方法是什么?

更新 1

我找到了 this article on mocking这似乎暗示写一个薄包装是要走的路。我不太清楚为什么,但我觉得这是一个 hack。话又说回来,它可以使代码更具表现力。

但这提出了一个问题,在 NSDate 的情况下,您是否将包装类注入(inject)到需要知道日期的每个类中?!当然不是...

更新 2

关于这个问题已经有一些很好的答案,但我仍在等待其他答案 - 一定有一个确定的方法,对吗?我仍然不明白类别如何给我一个我可以控制的虚拟对象。

最佳答案

一般来说,这是一个“如何模拟静态/类级方法”的问题,谷歌搜索显示了很多不同的想法,所以主要归结为品味。

我认为部分模拟是一种代码味道,因为它表明您的被测类 (CUT) 不可测试 -> 是时候重构了。

我过去用两种方式解决这个问题:

1.) 将 DateProvider(它是一个接口(interface))传递到 CUT 的构造函数中

interface DateProvider 
    date timenow()
end

在测试时,这是您的 MockDateProvider,您可以从测试类更改状态。我可能会使用可以在测试中更改的公共(public)静态字段

class MockDateProvider :: DateProvider
   public static field fakeDate   
   date timenow () 
      return fakedate
   end
end   

在实际系统中,它只有您使用的日期创建方法。

class RealDateProvider :: DateProvider
   date timenow()
      return LibraryDateMaker.newDate()
   end
end

我可能会制作 2 个构造函数,一个采用此接口(interface),另一个使用 RealDateProvider 而无需传入对象的任何生产类。

这是更可取的 OO 做事方式。我想!

2.) 制作您自己的静态日期提供程序,您可以覆盖其行为。

您将 ConfigurableDateMaker.newDate() 设为静态,而不是 LibraryDateMaker.newDate()。它使用与 1 相同的对象,但有一个 setter 允许您根据需要将行为更改为模拟提供者。默认为真实。

这样做的好处是你不必将任何东西传递给你的构造函数,你可以继续使用静态方法进行非常常见的事件。

简而言之,CUT 调用 ConfigurableDateMaker.newDate()。默认情况下返回真实日期,但在您的测试类中,您可以将行为设置为在调用 CUT 之前使用模拟。

class ConfigurableDateMaker
  public static DateProvider provider
   static date timenow()
      return provider.newDate()
   end
   // add the 2 provider classes as inner classes in here
end

希望这是有道理的。

关于objective-c - 你应该如何在 Objective C/Cocoa 中模拟你不拥有的类? (例如 NSDate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9344051/

相关文章:

objective-c - Objective-C 中应用程序的入口点

ios - 具有自动布局约束的 UIScrollView : Auto Content Size Calculation

objective-c - 应用图标问题上的远程通知角标(Badge)

objective-c - 模拟 CLLocationManager (swift) 用于测试

c++ - 如何在 AMOP 中创建没有接口(interface)类的模拟对象?

android - Mockito 1.9.5 + Android 上的 Dexmaker 在 Eclipse 中出现 NoClassDefFoundError

ios - 如何在 objective c iphone 的另一个字符串中追加一个字符串

iphone - 单击后表格单元格变为空白

unit-testing - 如何在 Grails 中使用静态成员模拟抽象类?

unit-testing - 为什么此模拟 'return'是一个Closure,而不是实际的返回值?