在斯威夫特嘲笑

你如何在Swift中模拟一个对象?

Mirror协议听起来很有希望,但现在并没有太多的工作。

到目前为止,我发现的唯一方法是inheritance并覆盖模拟类的所有方法。 这当然不是一个真正的模拟,远非理想,而是很多的工作。

任何其他的想法?

为什么不OCMock?

来源 :

我可以使用语言桥function使用OCMock吗?

是的,但有限制。 如果你很勇敢。 截至目前这是高度实验性的。 不能保证OCMock将永远支持Swift。

已知的限制:

  • testing必须写在Objective-C中
  • 应该被模拟的对象必须从NSObjectinheritance
  • 没有存根/期待/validation类方法

NSHipster涉及Swift中的语言特性,这使得外部嘲讽库不再必要:

在Swift中,类可以在函数的定义中声明,允许模拟对象是非常独立的。 只要声明一个模拟的内部类,重写和[原文如此]必要的方法:

 func testFetchRequestWithMockedManagedObjectContext() { class MockNSManagedObjectContext: NSManagedObjectContext { override func executeFetchRequest(request: NSFetchRequest!, error: AutoreleasingUnsafePointer<NSError?>) -> [AnyObject]! { return [["name": "Johnny Appleseed", "email": "johnny@apple.com"]] } } ... } 

在本地范围内创build外部依赖项的子类以及添加XCTestExpectation解决了许多与OCMock相同的问题。

OCMock这样的库提供的一个非常有用的东西是它的“validation”方法,以确保模拟类被调用。 可以手动添加,但自动添加是很好的。

我通过在协议中包装所有东西来创build我的模拟类。 我手动推出一个模拟类来符合有问题的协议,如下所示:

 protocol Dog: class { var name: String { get } func bark() } class DogImpl: Dog { var name: String init(name: String) { self.name = name } func bark() { print("Bark!") } } class DogMock: Dog { var name = "Mock Dog" var didBark = false func bark() { didBark = true } } 

我使用这个和dependency injection一起来实现全面的testing覆盖。 这是很多的样板,但到目前为止,我还没有任何问题。

关于子类嘲讽,你会碰到final类的麻烦,或者如果他们有不平凡的初始化器。

除了明显的答案之外,我想指出一些东西 – 我不知道这是否是一个错误。

如果你以某种方式inheritance NSObject(在我的情况下,我是inheritance NSObject内部子类的UIView),你需要用@objc声明overriden函数的显式,否则你的testing不会编译。 在我的情况下,编译器本身崩溃与以下:

分割错误:11

所以下面的课:

 public class ClassA: UIView { @objc public func johnAppleseed() { } } 

应按以下方式进行unit testing:

 class ClassATests: XCTestCase { func testExample() { class ClassAChildren: ClassA { @objc private override func johnAppleseed() { } } } } 

你可以用MockFive来实现这种嘲弄。

它的要点是你必须创build一个你想模拟的源代码类的“模拟手”

但是可以dynamic地存储它的方法,所以你可以在需要的地方使用它,并在那里configuration它的行为。

我写了一篇关于如何在这里使用的文章。