在斯威夫特嘲笑
你如何在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它的行为。
我写了一篇关于如何在这里使用的文章。