Итак, у меня есть класс из одной из наших внутренних структур. Он определяется следующим образом:
// This lives within a framework
class ExternalClass: ExternalClassProtocol {
// implementation here
}
// This lives within my test target
class MockExternalClass: ExternalClassProtocol {
// Mock implementation here
}
// This lives within the same external frame work as ExternalClass
protocol ExternalClassProtocol: AnyObject {
// Protocol methods here
}
Если я попытаюсь привести MockExternalClass в ходе моих тестовых случаев? ExternalClassProtocol, тестовый случай дает сбой.
Однако во время выполнения приложения в реальном времени нет проблем при приведении ExternalClass как? ExternalClassProtocol.
Это проблема при попытке реализовать протокол из внешнего модуля? Есть ли способ обойти это?
Доступ к классу осуществляется через внедрение зависимостей (см. Ниже реализацию внедрения зависимостей). Cra sh происходит в функции разрешения.
Если вы на самом деле отлаживаетесь до этой точки, вы можете видеть, что фиктивная зависимость ЕСТЬ в моей зависимости root (массив служб ниже).
Итак, я знаю, что его не удалось разыграть из-за отсутствия зависимости.
@propertyWrapper
struct Injected<Value> {
var key: String
var wrappedValue: Value {
get { return Dependency.root.resolve(key: self.key) }
set { Dependency.root.add(key: self.key, newValue) }
}
init(key: String) {
self.key = key
}
}
class Dependency {
static let root = Dependency()
var services: [String : Any] = [:]
func add<T>(key: String, _ service: T) {
services[key] = service
}
func resolve<T>(key: String) -> T {
guard let component: T = services[key] as? T else {
// The test crashes here. It works fine on other mocks that are internal to the project
fatalError("Dependency '\(T.self)' not resolved!")
}
return component
}
func clearDependencies() {
self.services.removeAll()
}
private init() {}
}
В моем тестовом примере:
@testable import MyProject
import ExternalDependency
class TestCase: XCTestCase {
private var subject: ClassWithService!
private var mockInternalClass: MockInternalClassProtocol!
private var mockExternalClass: MockInternallClassProtocol!
func setUp() {
mockExternalClass = MockExternalClass() // This one crashes when trying to cast to its parent protocol
mockInternalClass = MockInternalClass() // This one does not crash when casting to parent protocol.
Dependency.root.add(key: "internal_class", mockInternalClass)
Dependency.root.add(key: "external_class", mockExternalClass)
}
}
Некоторые вещи, которые я ' мы пробовали:
Добавление AnyObject к протоколу (это исправило аналогичную проблему для внутренне определенных классов, которые я высмеиваю).
изменение типа mockExternalClass на протокол, изменяющий тип mockExternalClass на реализацию
Помимо одного протокола, определяемого в одном из наших модулей, нет никакой разницы между внешним протоколом и тем, который мы определили в нашем собственном проекте.
Одна вещь, которую я заметил, заключается в том, что приведение не завершится ошибкой, если вы установите точку останова внутри одной из моих функций тестового примера. Но если вы попробуете то же самое приведение в функции Dependency.resolve, то произойдет сбой. Что заставляет меня верить, что есть проблема с генериками.
Есть идеи?