要在 UI 测试中使用 Catbird,您必须拥有 Catbird 服务器和 Catbird API 代码,以便与服务器进行通信。
类型 | 服务器 | API 代码 |
---|---|---|
手动 | ✅ | ✅ |
Homebrew | ✅ | 🚫 |
SPM | 🚫 | ✅ |
CocoaPods | ✅ | ✅ |
从最新版本页面下载 catbird.zip 压缩包。
运行以下命令
brew install RedMadRobot/formulae/catbird
如果您有一个 Xcode 项目,请打开它并使用以下 URL 添加 Catbird Package
https://github.com/RedMadRobot/catbird.git
将 Catbird
添加到 UI 测试目标。
target 'App' do
use_frameworks!
target 'AppUITests' do
inherit! :search_paths
pod 'Catbird'
end
end
Schema/Edit scheme...
Pre-Actions
New Run Script action
<YOUR_APP_TARGET>
提供构建设置${PODS_ROOT}/Catbird/start.sh
Post-Actions
New Run Script action
<YOUR_APP_TARGET>
提供构建设置${PODS_ROOT}/Catbird/stop.sh
import XCTest
import Catbird
enum LoginMock: CatbirdMockConvertible {
case success
case blockedUserError
var pattern: RequestPattern {
RequestPattern(method: .POST, url: URL(string: "/login")!)
}
var response: ResponseMock {
switch self {
case .success:
let json: [String: Any] = [
"data": [
"access_token": "abc",
"refresh_token": "xyz",
"expired_in": "123",
]
]
return ResponseMock(
status: 200,
headers: ["Content-Type": "application/json"],
body: try! JSONSerialization.data(withJSONObject: json))
case .blockedUserError:
let json: [String: Any] = [
"error": [
"code": "user_blocked",
"message": "user blocked"
]
]
return ResponseMock(
status: 400,
headers: ["Content-Type": "application/json"],
body: try! JSONSerialization.data(withJSONObject: json))
}
}
}
final class LoginUITests: XCTestCase {
private let catbird = Catbird()
private var app: XCUIApplication!
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
// Base URL in app `UserDefaults.standard.url(forKey: "url_key")`
app.launchArguments = ["-url_key", catbird.url.absoluteString]
app.launch()
}
override func tearDown() {
XCTAssertNoThrow(try catbird.send(.removeAll), "Remove all requests")
super.tearDown()
}
func testLogin() {
XCTAssertNoThrow(try catbird.send(.add(LoginMock.success)))
app.textFields["login"].tap()
app.textFields["login"].typeText("john@example.com")
app.secureTextFields["password"].tap()
app.secureTextFields["password"].typeText("qwerty")
app.buttons["Done"].tap()
XCTAssert(app.staticTexts["Main Screen"].waitForExistence(timeout: 3))
}
func testBlockedUserError() {
XCTAssertNoThrow(try catbird.send(.add(LoginMock.blockedUserError)))
app.textFields["login"].tap()
app.textFields["login"].typeText("peter@example.com")
app.secureTextFields["password"].tap()
app.secureTextFields["password"].typeText("burger")
app.buttons["Done"].tap()
XCTAssert(app.alerts["Error"].waitForExistence(timeout: 3))
}
}
您可以指定一个模式来捕获 http 请求,并使用模拟数据生成响应。 模式匹配适用于请求中的 URL 和 http 标头。 请参阅 RequestPattern
结构体。
可以使用三种类型的模式
equal
- 请求值必须与模式值完全相同,wildcard
- 请求值与通配符模式匹配(见下文),regexp
- 请求值与正则表达式模式匹配。如果要对 url 查询参数应用通配符模式,请不要忘记转义域名或路径后的 ?
符号。
Pattern.wildcard("http://example.com\?query=*")
“通配符”是您在命令行执行类似 ls *.js
的操作,或在 .gitignore
文件中放置 build/*
时输入的模式。
在我们的实现中,任何通配符模式都会转换为正则表达式,并应用于 URL 或标头字符串的匹配。
以下字符在模式中使用时具有特殊的魔法含义
*
匹配 0 个或多个字符?
匹配 1 个字符[a-z]
匹配一个字符范围,类似于 RegExp 范围。{bar,baz}
匹配大括号中列出的替换项之一。 例如,模式 foo{bar,baz}
匹配字符串 foobar
或 foobaz
您可以使用反斜杠 \
转义特殊字符。
不支持组中的否定。
$ cd Example/CatbirdX
$ bundle exec pod install
$ xed .
CATBIRD_MOCKS_DIR
— 静态 mocks 所在的目录。CATBIRD_RECORD_MODE
— 将此变量设置为 1
,以便应用程序开始沿着 CATBIRD_MOCKS_DIR
中设置的路径记录 HTTP 响应。 默认为 0
。CATBIRD_REDIRECT_URL
— 设置此 url 以将直接请求转发到 catbird。 默认为 nil。 如果未启用记录模式,则首先在 mocks 中搜索响应,如果找不到任何内容,则转发请求。CATBIRD_PROXY_ENABLED
— 将此变量设置为 1
以将代理请求转发到 catbird。 默认为 0
。 如果未启用记录模式,则首先在 mocks 中搜索响应,如果找不到任何内容,则代理请求。Catbird 仅支持代理 HTTP 请求。 不支持 HTTPS 请求!
使用 CATBIRD_REDIRECT_URL
运行 catbird。
CATBIRD_REDIRECT_URL=https://api.github.com ./catbird
所有直接请求都将转发到 CATBIRD_REDIRECT_URL
。
curl http://127.0.0.1:8080/zen
响应将返回到请求 https://api.github.com/zen
使用 CATBIRD_PROXY_ENABLED=1
运行 catbird。
CATBIRD_PROXY_ENABLED=1 ./catbird
通过启用此模式,catbird 将作为本地 http 代理服务器运行。 您可以将您的 http 客户端配置为使用此代理,所有请求都将通过 catbird 代理并重定向到实际主机。 如果您不想更改请求的基本 url,这可能会有所帮助。
curl http://api.github.com/zen --proxy http://127.0.0.1:8080
可以在 Console.app
中查看具有子系统 com.redmadrobot.catbird
的日志
不要忘记在操作菜单中包含消息
没有这个,只有错误消息是可见的
您可以在页面 http://127.0.0.1:8080/catbird 上查看所有拦截到的请求的列表
对于并行测试,您需要满足几个条件。
parallelId
标识符的 Catbird
实例。parallelId
传递给应用程序。parallelId
作为 X-Catbird-Parallel-Id 添加到应用程序中的每个请求标头。final class LoginUITests: XCTestCase {
private let catbird = Catbird(parallelId: UUID().uuidString)
private var app: XCUIApplication!
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments = [
// Base URL in app `UserDefaults.standard.url(forKey: "url_key")`
"-url_key", catbird.url.absoluteString,
// `parallelId` in app `UserDefaults.standard.url(forKey: "parallelId")`
"-parallelId", catbird.parallelId!
]
app.launch()
}
}