Внедрение зависимостей: статические методы и параметры - PullRequest
0 голосов
/ 27 апреля 2018

Я пытаюсь добавить модульные тесты в программу Swift, которая размещена в библиотеке Objective-C. В настоящее время моей главной проблемой является поиск способа внедрения зависимости, созданной с помощью параметризованного статического метода фабрики.

В качестве примера следующий код является функциональным, но довольно устойчивым к испытаниям:

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'
    }
}

Обратите внимание, что RegistrationServiceProvider, RegistrationService и Configuration все из библиотеки Objective-C.

Что я хотел бы сделать, так это предоставить RegistrationService, созданный в этом коде, по умолчанию и заменить его на мой собственный макет при тестировании. Без объекта Configuration было бы довольно просто использовать что-то вроде http://www.danielhall.io/swift-y-dependency-injection-part-two.

(Я понимаю, что мог бы / должен передать конструкцию Configuration вызывающей стороне, но это не решает проблему ее доставки в службу по умолчанию.)

Предложения и ссылки приветствуются.

Ответы [ 2 ]

0 голосов
/ 22 мая 2019

Я получил немного отличную реализацию, чем принятый выше ответ, используя протокол вместо наследования. Я не верю, что это лучшая реализация. Просто личное предпочтение. Для определения протокола требуется дополнительный код.

protocol ServiceProvidable {
   func registrationService(configuration: Configuration) -> RegistrationService
}

Это изменит параметры функции register на ...

func register(user: String, pass: String, serviceProvider: ServiceProvidable.Type = RegistrationServiceProvider.self)

и поставщик будет соответствовать протоколу ...

class RegistrationServiceProvider: ServiceProvidable

Теперь ваши фиктивные провайдеры могут просто придерживаться протокола и реализовывать требуемую функцию без переопределения. Вы также получаете дополнительное преимущество, позволяя Xcode заглушить функцию. Не большое дело, но небольшое удобство.

Просто другой взгляд на стиль программирования, ориентированный на протокол.

0 голосов
/ 27 апреля 2018

Вы можете создать макет из 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...