在swift单元测试中快速模拟静态类方法?
我是一名经验丰富的Objective-c程序员,但我不能对Swift说同样的话,我很难在没有使用OCMock等框架的情况下在Swift中对类进行单元测试 问题:我正在将Firebase集成到一个混合的Objective-C/Swift项目中,我需要根据应用程序的构建配置对其进行配置 我已经为此编写了一个Swift类(obj-c应用程序代表将使用该类),但是由于firebase框架是通过静态类方法配置的,精确地说是在swift单元测试中快速模拟静态类方法?,swift,unit-testing,dependency-injection,xctest,swift-protocols,Swift,Unit Testing,Dependency Injection,Xctest,Swift Protocols,我是一名经验丰富的Objective-c程序员,但我不能对Swift说同样的话,我很难在没有使用OCMock等框架的情况下在Swift中对类进行单元测试 问题:我正在将Firebase集成到一个混合的Objective-C/Swift项目中,我需要根据应用程序的构建配置对其进行配置 我已经为此编写了一个Swift类(obj-c应用程序代表将使用该类),但是由于firebase框架是通过静态类方法配置的,精确地说是FIRApp.configure(with:FIROptions),我需要以某种方式
FIRApp.configure(with:FIROptions)
,我需要以某种方式模拟该方法,以便对其进行单元测试
我的代码没有任何依赖项注入句柄,如下所示:
@objc class FirebaseConfigurator: NSObject{
func configureFirebase(){
let config = configManager.buildConfiguration
var optionsPlistBaseName = getPlistName()
let optionsFile = Bundle.main.path(forResource: optionsPlistBaseName, ofType: "plist")
guard let opts = FIROptions(contentsOfFile: optionsFile) else{
assert(false, "fatal: unable to load \(optionsFile)")
return
}
FIRApp.configure(with: opts)
}
func getPlistName() -> String{
// retrieves correct plist name and returns it
}
}
我做了一些研究,但到目前为止,我没有找到任何适合我的解决方案,但我想到了以下一个:
- 我可以传递一个默认为
的函数,但是我应该从objective-c执行此操作,并且该函数也接受一个参数,我正在努力使用语法FIRApp.configure(with:)
- 我可以在FIRApp周围使用一个包装,但我想避免它,除非它是唯一可行的清洁解决方案
- 我可以继续玩协议和进行依赖项反转,但是作为静态方法,我又在为语法而挣扎,我找不到一种简单的方法来使用静态方法的模拟类进行DI
作为旁注,我有很多方法可以解决这个问题,而不必费劲模仿静态类方法,但我的目标是找到一种模仿它的方法,以便在测试更复杂的情况时更好地理解最佳实践。您确实可以做其中任何一种 闭包参数 您可以让
configureFirebase
函数采用默认为您最初使用的“applier”闭包:
func configureFirebase(
using apply: (_ options: FIROptions) -> Void
= { opts in FIRApp.configure(opts) }
) {
// building |opts| as before
// Now replace this: FIRApp.configure(with: opts)
apply(opts)
}
协议
您需要一个可配置的
协议,然后在默认情况下使其符合FIRApp
:
protocol Configurable {
static func configure(with options: FIROptions)
}
extension FIRApp: Configurable {}
class FirebaseConfigurator {
var configurable: Configurable
init(configurable: Configurable = FIRApp) {
self.configurable = configurable
}
func configureFirebase() {
//load |opts|…
configurable.configure(with: opts)
}
}
如果你只想在一个方法中使用它,它只是一个瞬态,它应该是一个函数参数,而不是存储的属性
(如果不清楚它是持久状态还是暂时状态,因为类的全部目的是调用单个函数,那么您甚至不需要类,只需要一个函数。)最后,我不需要再处理这个问题,但无论如何,感谢您的回答;)。这是一个很难回答的问题,applier闭包有一个默认值,这个值是否连接到objective-c?我怀疑它没有像前面写的那样连接,但是如果必须的话,您可以通过一种可连接的方式完成同样的事情。