依赖注入:静态方法和参数

Phi*_*lls 2 unit-testing dependency-injection swift

我正在尝试将单元测试添加到位于 Objective-C 库之上的 Swift 程序。我目前的主要问题是找到一种方法来注入使用参数化静态工厂方法创建的依赖项。

例如,以下代码可以正常运行,但难以测试:

class Processor {
    var service: RegistrationService?

    func register(user: String, pass: String) {
        let configuration = Configuration(user: user, pass: pass)
        service = RegistrationServiceProvider.registrationService(configuration: configuration)

        // Do various things with the 'service'
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意RegistrationServiceProvider, 、RegistrationService、 和Configuration均来自 Objective-C 库。

我希望能够做的是提供RegistrationService在此代码中创建的默认值,并在测试时将其替换为我自己的模拟。如果没有该对象,使用http://www.danielhall.io/swift-y-dependency-injection-part-twoConfiguration之类的东西会相当简单。

(我意识到我可以/应该将Configuration构造推送给调用者,但这并不能解决如何将其提供给默认服务的问题。)

欢迎提出建议和参考。

小智 6

您可以创建 RegistrationService 和 RegistrationServiceProvider 的模拟,并将它们注入到测试中,使用标准 Type 作为正常调用中的默认类型,如下面的代码(它包括您使用的类的示例版本和一些打印输出)什么叫):

class Configuration {
    let user: String
    let pass: String

    init(user: String, pass: String) {
        self.user = user
        self.pass = pass
    }
}

class RegistrationService {
    let configuration: Configuration

    init(configuration: Configuration) {
        self.configuration = configuration
    }
}

class RegistrationServiceProvider {

    class func registrationService(configuration: Configuration) -> RegistrationService {
        print("Provider instantiated service")
        return RegistrationService(configuration: configuration)
    }
}

class Processor {
    var service: RegistrationService?
    func register(user: String, pass: String, serviceProvider: RegistrationServiceProvider.Type = RegistrationServiceProvider.self) {
        let configuration = Configuration(user: user, pass: pass)
        service = serviceProvider.registrationService(configuration: configuration)

        // Do various things with the 'service'
    }
}

class MockProvider: RegistrationServiceProvider {
    override class func registrationService(configuration: Configuration) -> RegistrationService {
        print("Mock provider instantiated mock service")
        return MockService(configuration: configuration)
    }
}

class MockService: RegistrationService {
    override init(configuration: Configuration) {
        super.init(configuration: configuration)
        print("Mock service initialized")
    }
}

let processor = Processor()

processor.register(user: "userName", pass: "myPassword") // Provider instantiated service

processor.register(user: "userName", pass: "myPassword", serviceProvider: MockProvider.self) // Mock provider instantiated mock service
Run Code Online (Sandbox Code Playgroud)