首页 > 解决方案 > 依赖注入:静态方法和参数

问题描述

我正在尝试将单元测试添加到分层在 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'
    }
}

请注意RegistrationServiceProviderRegistrationService、 和Configuration都来自 Objective-C 库。

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

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

欢迎提出建议和参考。

标签: swiftunit-testingdependency-injection

解决方案


您可以创建 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

推荐阅读