swift-mimic 0.3.0

swift-mimic 0.3.0

Taylan Pince 维护。



Version License Platform Swift 4.2

概述

Swift-Mimic 是一个库,用于使用最少的代码更改模拟网络请求。它可以用于

  • 将单元测试和 UI 测试转换为在模拟 API 响应上运行,最小化测试维护并优化测试速度
  • 在新功能准备好实际 API 端点之前开发新功能,只需少量代码更改

Swift-Mimic 被设计为包含所有部件、易于集成的解决方案,具有几个可扩展的功能

  • 基于文件的模拟捆绑包,反映了 API 端点结构,并附带基础 URL
  • 支持多个模拟捆绑包套件,可以根据不同的测试场景进行层叠覆盖
  • 可交换的模拟捆绑协议,如果需要,可以开发自己的高级捆绑格式
  • 自动发现模拟捆绑包中的端点,因此默认场景不需要代码
  • 使用三条代码即可与任何现有的单元或 UI 测试集成

安装

我们建议使用 Cocoapods 进行安装

pod 'swift-mimic'

重要:由于一个已知的 Cocoapods 问题,UI 测试可能无法编译。目前记录的解决方案是将以下 post_install 钩子包括在您的 Podfile

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            # This works around a unit test issue introduced in Xcode 10.
            # We only apply it to the Debug configuration to avoid bloating the app size
            if config.name == "Debug" && defined?(target.product_type) && target.product_type == "com.apple.product-type.framework"
                config.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = "YES"
            end
        end
    end
end

配置

创建模拟包

在配置应用程序使用《Swift-Mimic》之前,第一步是创建一个API模拟包。有几种方法可以做到这一点,从手动生成文件夹和文件结构到使用记录器框架,如SWHttpTrafficRecorder

模拟包的结构很简单。假设您有一个提供以下端点的API

假设您将模拟以下请求

然后您的模拟包结构应该是这样的

  • Mocks.bundle
    • api
      • authenticate
        • post.json
      • users
        • get.json
      • projects
        • get_200.json
        • post_201.json

列表中的每个JSON文件都应该包含要模拟的API响应。文件名可以提供两种格式:HTTP METHOD.jsonHTTP METHOD_RESPONSE CODE.json。如果您没有提供响应代码,则《Swift-Mock》将假设匹配的HTTP方法是默认文件,并将其优先级高于其他文件。

您可以在Xcode项目中添加该包的任何位置,但是确保它同时与主应用程序目标以及测试目标链接。

您可以创建任意数量的包,以便在单个基本URL下组织端点或支持多个API URL下的模拟。

更新网络集成

为了使《Swift-Mimic》能够在不添加额外代码的情况下覆盖网络请求,您需要将一个特殊配置传递给API请求层使用的活动《URLSession》。这很容易做到,以下是一个使用《Alamofire》的示例

if let mockUrlSessionConfiguration = MimicSession.shared?.urlSessionConfiguration {
  sessionManager = Alamofire.SessionManager(configuration: mockUrlSessionConfiguration)
} else {
  sessionManager =  SessionManager.default
}

这是一个标准的《URLSessionConfiguration》对象,因此它可以传递给任何在《URLSession》上运行的任何网络层,包括苹果的原始实现。

设置测试套件

最后一步是在您的测试层中定义您的模拟套件,以便测试运行器知道它配置的模拟。这里是最简单的实现方式

import XCTest
import swift_mimic


extension XCUIApplication: MimicUIApplication {
    
}


class ExampleTest: XCTestCase {

    var app: XCUIApplication = XCUIApplication()
    
    override func setUp() {
        continueAfterFailure = false

        let suite = MIMMockSuite(baseURL: "https://my-service.com", bundleNames: "Mocks")

        try? MimicLauncher.launch(app, with: [suite])
    }

}

这里有几个事情在进行。首先,我们要确保 XCUIApplication 被配置为包括 MimicUIApplication。你只需要在测试目标中完成这一步,而且只需一次。

然后,我们创建一个指向项目中的正确包的 MIMMockSuite 实例,并将其与我们要覆盖的 API 基础 URL 配对。

最后,我们使用我们刚刚创建的套件调用 MimicLauncher,以便它可以在配置中包含它。

你可以创建尽可能多的套件,并按你想它们被加载的顺序将它们传递给启动器。比如说,你有一个针对测试套件的特殊认证案例。如果不同基础 URL 对于案例是必需的,你可以通过以下方式利用套件的级联性质来实现:

class ExampleTest: XCTestCase {

    var app: XCUIApplication = XCUIApplication()
    
    override func setUp() {
        let suite = MIMMockSuite(baseURL: "https://my-service.com", bundleNames: "Mocks")
        let adminSuite = MIMMockSuite(baseURL: "https://my-second-service.com", bundleNames: "AdminMocks")

        try? MimicLauncher.launch(app, with: [suite, adminSuite])
    }

}

如果你的这两种情况都使用相同的基 URL,你应该使用以下结构:

class ExampleTest: XCTestCase {

    var app: XCUIApplication = XCUIApplication()

    override func setUp() {
        let suite = MIMMockSuite(baseURL: "https://my-service.com", bundleNames: ["Mocks", "AdminMocks"])

        try? MimicLauncher.launch(app, with: [suite])
    }

}

套件将按照数组中的倒序,从最后一个元素到第一个元素优先级进行排序。

发行历史

  • 0.3.0 - 2019 年 1 月 15 日
    • 添加自动发现和更简单的基本设置
  • 0.2.5 - 2019 年 1 月 14 日
    • 添加文档
  • 0.2.3 - 2019 年 1 月 13 日
    • 第一个稳定版本,包含完整示例项目

鸣谢

Hipo 团队构建,贡献者包括:

  • Goktug Berk Ulu
  • Eray Diler
  • Salih Karasuluoglu
  • Taylan Pince

贡献

  1. 分叉它 (https://github.com/Hipo/swift-mimic/fork)
  2. 创建您的功能分支 (git checkout -b feature/fooBar)
  3. 提交您的更改 (git commit -am '添加一些 fooBar')
  4. 将更改推送到分支 (git push origin feature/fooBar)
  5. 创建新的拉取请求

许可证

在 MIT 许可证下分发。有关更多信息,请参阅 LICENSE 文件。