DependencyFetcher 1.0.0

DependencyFetcher 1.0.0

Sergej Jaskiewicz 维护。



Build Status codecov Language Platform Cocoapods

Swift 最简单的依赖注入框架。

  • 线程安全。
  • 只有大约 60 行源代码。
  • 适用于任何平台,包括 Linux,不依赖于 Foundation。
  • 不使用全局状态。
  • 根本不需要任何配置。

在应用代码中获取依赖项

在某处代码中创建一个Fetcher实例

let fetcher = Fetcher.createDefault()

然后可以通过,例如,通过初始化器注入来传递这个实例。没错,你不需要在除将它们定义为Service类的静态属性之外的地方注册你的服务。

当你需要依赖项时,只需调用

let logger = self.fetcher.fetch(.logger) // logger has the type Logger
let database = self.fetcher.fetch(.database) // database has the type Database

在测试中模拟服务

你的应用代码不需要(甚至不应该是)知道它是否在测试期间执行。当你需要模拟依赖项时,只需创建一个Fetcher实例,并用它们的模拟重写需要的服务。

let fetcher = Fetcher
  .create()
  .addOverride(for: Service.logger, instance: MockLogger())
  .addOverride(for: Service.database, instance: MockDatabase())
  .done()

然后将这个实例传递到你要测试的单元中。

提取硬编码的依赖项

通常,你有一个很大的代码库,其中使用硬编码的依赖项(单例等)到处都是,你无法一次重构所有代码。《DependencyFetcher》可以逐步引入到你的代码库中。

假设你有一个视图控制器这样做(相当常见的MVC代码)

class ViewController: UIViewControlelr {

  var products: [Product] = []
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    APIEndpoint.default.getProducts(onSuccess: { self.products = $0 },
                                    onError: {error in /*...*/ })
  }
}

这非常难测试。我们可以进行一点重构

protocol APIEndpointProtocol {
  func getProducts(onSuccess: @escaping ([Product]) -> Void,
                   onError: @escaping (Error) -> Void)
}

extension APIEndpoint: APIEndpointProtocol {}

extension Service where T == APIEndpointProtocol {
  static let apiEndpoint = Service(APIEndpoint.default)
}

class ViewController: UIViewControlelr {

  var products: [Product] = []
  
  var fetcher = Fetcher.createDefault()
  
  private lazy var apiEndpoint = self.fetcher.fetch(.apiEndpoint)
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    self.apiEndpoint.getProducts(onSuccess: { self.products = $0 },
                                 onError: { error in /*...*/ })
  }
}

现在我们可以很容易地测试我们的ViewController

class MockAPIEndpoint: APIEndpointProtocol {
  
  let testProducts: [Product] = [
    // ...
  ]

  func getProducts(onSuccess: @escaping ([Product]) -> Void,
                   onError: @escaping (Error) -> Void) {
    onSuccess(self.testProducts)                 
  }
}
func testPopulatingViewControllerWithProducts() {
  let vc = ViewController()
  let mock = MockAPIEndpoint()
  vc.fetcher = Fetcher
    .create()
    .addOverride(for: Service.apiEndpoint, instance: mock)
    .done()
    
  vc.viewDidLoad()
  
  XCTAssertEqual(vc.products, mock.testProducts)
}

安装

Swift包管理器

在你Package.swift文件中添加以下内容

dependencies: [
  .package(url: "https://github.com/broadwaylamb/DependencyFetcher.git",
           from: "1.0.0"),
]

CocoaPods

在您的 Podfile 中添加以下内容:

target 'MyApp' do
  pod 'DependencyFetcher', '~> 1.0'
end