【发布时间】:2016-05-07 18:59:11
【问题描述】:
我有一个要使用 XCTest 测试的类,这个类看起来像这样:
public class MyClass: NSObject {
func method() {
// Do something...
// ...
SingletonClass.sharedInstance.callMethod()
}
}
这个类使用了一个这样实现的单例:
public class SingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SingletonClass()
private override init() {
super.init()
}
func callMethod() {
// Do something crazy that shouldn't run under tests
}
}
现在开始测试。我想测试method() 确实做了它应该做的事情,但我不想调用callMethod() 中的代码(因为它做了一些不应该在测试下运行的可怕的异步/网络/线程的东西MyClass,并且会使测试崩溃)。
所以我基本上想做的是:
SingletonClass = MockSingletonClass: SingletonClass {
override func callMethod() {
// Do nothing
}
let myObject = MyClass()
myObject.method()
// Check if tests passed
这显然不是有效的 Swift,但你明白了。我如何才能仅针对此特定测试覆盖 callMethod() 以使其无害?
编辑:我尝试使用依赖注入的形式解决这个问题,但遇到了大问题。我创建了一个自定义 init 方法,仅用于测试,这样我就可以像这样创建我的对象:
let myObject = MyClass(singleton: MockSingletonClass)
让 MyClass 看起来像这样
public class MyClass: NSObject {
let singleton: SingletonClass
init(mockSingleton: SingletonClass){
self.singleton = mockSingleton
}
init() {
singleton = SingletonClass.sharedInstance
}
func method() {
// Do something...
// ...
singleton.callMethod()
}
}
将测试代码与其余代码混合在一起我觉得有点不愉快,但没关系。最大的问题是我的项目中有两个像这样构造的单例,它们都相互引用:
public class FirstSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = FirstSingletonClass()
let secondSingleton: SecondSingletonClass
init(mockSingleton: SecondSingletonClass){
self.secondSingleton = mockSingleton
}
private override init() {
secondSingleton = SecondSingletonClass.sharedInstance
super.init()
}
func someMethod(){
// Use secondSingleton
}
}
public class SecondSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SecondSingletonClass()
let firstSingleton: FirstSingletonClass
init(mockSingleton: FirstSingletonClass){
self.firstSingleton = mockSingleton
}
private override init() {
firstSingleton = FirstSingletonClass.sharedInstance
super.init()
}
func someOtherMethod(){
// Use firstSingleton
}
}
当第一次使用其中一个单例时,这会造成死锁,因为 init 方法会等待另一个的 init 方法,依此类推...
【问题讨论】:
标签: swift mocking singleton xctest