Mocker 2.5.5

Mocker 2.5.5

Antoine v.d. LeeAntoine v.d. Lee 维护。



Mocker 2.5.5

Mocker 是一个用 Swift 编写的库,它通过自定义 URLProtocol 使数据请求的模拟成为可能。

功能

在不离开本地网络的情况下运行您所有的数据请求单元测试 🎉

  • 基于 URL 创建模拟数据请求
  • 基于文件扩展名创建模拟数据请求
  • 与使用自定义协议类的 URLSession 配合工作
  • 支持像 Alamofire 这样的流行框架

使用方法

Mocker 编写了单元测试,这可以帮助您了解其工作原理。

激活 Mocker

在注册第一个 Mock 之后,Mocker 将自动为默认的 URL 加载系统(如 URLSession.shared)启动。

自定义 URLSessions

为了让它与您的自定义 URLSession 兼容,需要注册 MockingURLProtocol

let configuration = URLSessionConfiguration.default
configuration.protocolClasses = [MockingURLProtocol.self]
let urlSession = URLSession(configuration: configuration)
Alamofire

与在自定义 URLSession 上注册相当类似。

let configuration = URLSessionConfiguration.af.default
configuration.protocolClasses = [MockingURLProtocol.self]
let sessionManager = Alamofire.Session(configuration: configuration)

注册模拟

创建您的模拟数据

建议创建一个类,使所有模拟数据可访问。该项目单元测试中的示例。

public final class MockedData {
    public static let botAvatarImageResponseHead: Data = try! Data(contentsOf: Bundle(for: MockedData.self).url(forResource: "Resources/Responses/bot-avatar-image-head", withExtension: "data")!)
    public static let botAvatarImageFileUrl: URL = Bundle(for: MockedData.self).url(forResource: "wetransfer_bot_avater", withExtension: "png")!
    public static let exampleJSON: URL = Bundle(for: MockedData.self).url(forResource: "Resources/JSON Files/example", withExtension: "json")!
}
JSON 请求
let originalURL = URL(string: "https://www.wetransfer.com/example.json")!
    
let mock = Mock(url: originalURL, dataType: .json, statusCode: 200, data: [
    .get : try! Data(contentsOf: MockedData.exampleJSON) // Data containing the JSON response
])
mock.register()

URLSession.shared.dataTask(with: originalURL) { (data, response, error) in
    guard let data = data, let jsonDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
        return
    }
    
    // jsonDictionary contains your JSON sample file data
    // ..
    
}.resume()
忽略查询

一些如身份验证 URL 的网址查询中包含时间戳或 UUID。为了模拟这些,您可以忽略特定 URL 的查询。

/// Would transform to "https://www.example.com/api/authentication" for example.
let originalURL = URL(string: "https://www.example.com/api/authentication?oauth_timestamp=151817037")!
    
let mock = Mock(url: originalURL, ignoreQuery: true, dataType: .json, statusCode: 200, data: [
    .get : try! Data(contentsOf: MockedData.exampleJSON) // Data containing the JSON response
])
mock.register()

URLSession.shared.dataTask(with: originalURL) { (data, response, error) in
    guard let data = data, let jsonDictionary = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
        return
    }
    
    // jsonDictionary contains your JSON sample file data
    // ..
    
}.resume()
文件扩展名
let imageURL = URL(string: "https://www.wetransfer.com/sample-image.png")!

Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 200, data: [
    .get: try! Data(contentsOf: MockedData.botAvatarImageFileUrl)
]).register()

URLSession.shared.dataTask(with: imageURL) { (data, response, error) in
    let botAvatarImage: UIImage = UIImage(data: data!)! // This is the image from your resources.
}.resume()
自定义HEAD和GET响应
let exampleURL = URL(string: "https://www.wetransfer.com/api/endpoint")!

Mock(url: exampleURL, dataType: .json, statusCode: 200, data: [
    .head: try! Data(contentsOf: MockedData.headResponse),
    .get: try! Data(contentsOf: MockedData.exampleJSON)
]).register()

URLSession.shared.dataTask(with: exampleURL) { (data, response, error) in
	// data is your mocked data
}.resume()
延迟响应

有时你需要测试请求取消功能是否正常工作。在这种情况下,模拟请求不应直接完成,你需要延迟。这可以轻松地添加。

let exampleURL = URL(string: "https://www.wetransfer.com/api/endpoint")!

var mock = Mock(url: exampleURL, dataType: .json, statusCode: 200, data: [
    .head: try! Data(contentsOf: MockedData.headResponse),
    .get: try! Data(contentsOf: MockedData.exampleJSON)
])
mock.delay = DispatchTimeInterval.seconds(5)
mock.register()
重定向响应

有时你想模拟短URL或其他的重定向URL。这通过保存响应并模拟重定向位置,这个位置可以在响应内部找到来实现。

Date: Tue, 10 Oct 2017 07:28:33 GMT
Location: https://wetransfer.com/redirect

通过为短URL和重定向URL创建模拟,你可以模拟重定向并测试这种行为。

let urlWhichRedirects: URL = URL(string: "https://we.tl/redirect")!
Mock(url: urlWhichRedirects, dataType: .html, statusCode: 200, data: [.get: try! Data(contentsOf: MockedData.redirectGET)]).register()
Mock(url: URL(string: "https://wetransfer.com/redirect")!, dataType: .json, statusCode: 200, data: [.get: try! Data(contentsOf: MockedData.exampleJSON)]).register()
忽略URL

由于模拟器默认情况下捕获所有注册的URL,你可能不需要模拟请求却抛出fatalError。在这种情况下,你可以忽略该URL。

let ignoredURL = URL(string: "www.wetransfer.com")!
Mocker.ignore(ignoredURL)

然而,如果你需要模拟器仅捕获模拟URL并忽略其他URL,你可以将mode属性设置为.optin

Mocker.mode = .optin

如果你想将原始模式设置回默认,只需将其设置为.optout即可。

Mocker.mode = .optout
模拟错误

你可以请求一个Mock返回一个错误,允许测试错误处理。

Mock(url: originalURL, dataType: .json, statusCode: 500, data: [.get: Data()],
     requestError: TestExampleError.example).register()

URLSession.shared.dataTask(with: originalURL) { (data, urlresponse, err) in
    XCTAssertNil(data)
    XCTAssertNil(urlresponse)
    XCTAssertNotNil(err)
    if let err = err {
        // there's not a particularly elegant way to verify an instance
        // of an error, but this is a convenient workaround for testing
        // purposes
        XCTAssertEqual("example", String(describing: err))
    }

    expectation.fulfill()
}.resume()
Mock回调

您可以在Mock回调上注册,以便使测试更加简单。

var mock = Mock(url: request.url!, dataType: .json, statusCode: 200, data: [.post: Data()])
mock.onRequest = { request, postBodyArguments in
    XCTAssertEqual(request.url, mock.request.url)
    XCTAssertEqual(expectedParameters, postBodyArguments as? [String: String])
    onRequestExpectation.fulfill()
}
mock.completion = {
    endpointIsCalledExpectation.fulfill()
}
mock.register()
Mock预期

除了设置completiononRequest之外,您还可以使用预期。

var mock = Mock(url: url, dataType: .json, statusCode: 200, data: [.get: Data()])
let requestExpectation = expectationForCompletingMock(&mock)
let completionExpectation = expectationForCompletingMock(&mock)
mock.register()

URLSession.shared.dataTask(with: URLRequest(url: url)).resume()

wait(for: [requestExpectation, completionExpectation], timeout: 2.0)

通信

  • 如果发现错误,请提交问题。
  • 如果您有功能请求,请提交问题。
  • 如果您想贡献,提交拉取请求。

安装

CocoaPods

CocoaPods 是Cocoa项目的依赖管理器。您可以使用以下命令来安装它:

$ gem install cocoapods

要使用CocoaPods将Mocker集成到您的Xcode项目中,请将其指定在您的Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'Mocker', '~> 2.5.4'
end

然后,运行以下命令

$ pod install

Carthage

Carthage 是一个去中心化的依赖管理器,可以构建您的依赖并提供二进制框架。

您可以使用以下命令使用 Homebrew 安装 Carthage:

$ brew update
$ brew install carthage

要使用 Carthage 将 Mocker 集成到您的 Xcode 项目中,请在您的 Cartfile 中指定它。

github "WeTransfer/Mocker" ~> 2.3.0

运行 carthage update 以构建框架,并将构建的 Mocker.framework 拖放到您的 Xcode 项目中。

Swift Package Manager

Swift Package Manager 是一个用于管理 Swift 代码分发的工具。它与 Swift 构建系统集成,以自动化下载、编译和链接依赖项的过程。

清单文件

将 Mocker 作为包添加到您的 Package.swift 文件中,然后将其指定为 Target(您希望在其中使用它的目标)的依赖项。

import PackageDescription

let package = Package(
    name: "MyProject",
    platforms: [
       .macOS(.v10_15)
    ],
    dependencies: [
        .package(url: "https://github.com/WeTransfer/Mocker.git", .upToNextMajor(from: "2.3.0"))
    ],
    targets: [
        .target(
            name: "MyProject",
            dependencies: ["Mocker"]),
        .testTarget(
            name: "MyProjectTests",
            dependencies: ["MyProject"]),
    ]
)

Xcode

要将 Mocker 作为依赖项添加到您的 Xcode 项目中,请选择 File > Swift Packages > Add Package Dependency 并输入仓库 URL。

解决构建错误

如果您遇到以下错误:找不到自动链接库 XCTest 和 XCTestSwiftSupport,请将以下属性从无切换到是。
ENABLE_TESTING_SEARCH_PATHS 为是

手动

如果您不想使用上述任何依赖项管理器,您可以将 Mocker 手动集成到项目中。

嵌入式框架

  • 打开终端,使用cd命令进入顶层项目目录,如果您的项目未初始化为Git仓库,请运行以下命令

    $ git init
  • 通过运行以下命令将Mocker添加为Git子模块

    $ git submodule add https://github.com/WeTransfer/Mocker.git
  • 打开新的Mocker 文件夹,并将Mocker.xcodeproj拖放到您应用程序的Xcode项目的项目导航器中。

    它应该嵌套在您应用程序的蓝色项目图标下。它是在所有其他Xcode组之上还是之下无关紧要。

  • 在项目导航器中选择Mocker.xcodeproj,并核实部署目标与您的应用程序目标相匹配。

  • 接下来,在项目导航器中(蓝色项目图标)选择您的应用程序项目,以进入目标配置窗口,并在侧栏的“targets”标题下选择应用程序目标。

  • 在窗口顶部的标签栏中,打开“General”面板。

  • 在“Embedded Binaries”部分的+按钮上单击。

  • 选择Mocker.framework

  • 这样就可以了!

    Mocker.framework将自动添加为目标依赖、链接框架和嵌入框架,在复制文件构建阶段完成,这是在模拟器和设备上构建所需的所有内容。


发布说明

查看CHANGELOG.md以获取变更列表。

许可协议

Mocker在MIT许可协议下提供。有关更多信息,请参阅LICENSE文件。