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

注意RegistrationServiceProviderRegistrationServiceConfiguration都来自Objective-C库。
我想做的是提供在这段代码中创建的RegistrationService作为默认值,并在测试时用我自己的mock替换它。如果没有Configuration对象,使用类似http://www.danielhall.io/swift-y-dependency-injection-part-two的方法会相当简单。
(我意识到我可以/应该将Configuration构造推送到调用方,但这并不能解决如何将其提供给默认服务的问题。)
欢迎提出建议和参考。

最佳答案

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

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

09-11 19:45