如何在 Xcode 10 和 macOS 10.14 下为 XCTest UI 测试启动 WireMock?
How can I launch WireMock for XCTest UI tests under Xcode 10 and macOS 10.14?
我们正在使用一个独立的 wiremock 实例作为我们 Xcode UI 测试的模拟服务器。我们有一个测试观察者 class 负责启动此实例(如果需要)并在测试完成后将其拆除 运行。观察者的代码如下:
import AppKit
import XCTest
import WiremockClient
class SSUITestObserver: NSObject, XCTestObservation {
enum TestObserverError : Error {
case MockServerStartupError(String)
}
lazy var testBundleURL: URL = Bundle(for: SSUITestCase.self).bundleURL
lazy var testBundleBinURL: URL = self.testBundleURL.appendingPathComponent("..", isDirectory: true)
lazy var mockServerHomeURL: URL = self.testBundleURL.appendingPathComponent("Contents/Resources/", isDirectory: true)
lazy var mockServerJarURL: URL = self.mockServerHomeURL.appendingPathComponent("wiremock-standalone-2.18.0.jar", isDirectory: false)
override init() {
super.init()
NSLog("UI Test Observer Initialized")
XCTestObservationCenter.shared.addTestObserver(self)
}
func testBundleWillStart(_ testBundle: Bundle) {
NSLog("***Test Bundle starting")
do {
// Start the Wiremock server
try ensureMockServerIsRunning()
} catch {
fatalError("\n Failed during test bundle setup: \(error)\n")
}
}
public func testBundleDidFinish(_ testBundle: Bundle) {
NSLog("***Test Bundle completed")
stopMockServer()
}
func ensureMockServerIsRunning() throws {
WiremockClient.baseURL = SSUIIntegrationTestCase.mockServerAddress
guard !WiremockClient.isServerRunning() else { return }
let args = ["-jar",
self.mockServerJarURL.path,
"--port", "3000",
"--root-dir", self.mockServerHomeURL.path]
_ = Process.launchedProcess(launchPath: "/usr/bin/java", arguments: args)
for _ in 1...9 {
if WiremockClient.isServerRunning() { return }
sleep(1)
}
throw TestObserverError.MockServerStartupError("Error staring up the mock server instance!")
}
func stopMockServer() {
WiremockClient.shutdownServer()
}
func resetMockServerStubs() {
WiremockClient.reset()
}
}
在我迁移到 macOS 10.14 之前一切都很好。以前,我们没有对 UITest 目标进行代码签名。在移动到 10.14 后,运行ning 测试现在在测试甚至开始 运行 之前失败并出现 bootstrap 错误。我发现为测试打开自动代码签名可以解决这个问题。
然而,这会导致第二个问题:在上面的 launchedProcess
行中,启动 Wiremock 服务器的尝试将失败并显示 java.lang.RuntimeException: java.net.SocketException: Operation not permitted
。如果在我执行测试之前启动服务器(例如在命令行上),一切正常。
那么我怎样才能摆脱这个第 22 条军规呢?在 10.13 下一切正常。我不清楚代码签名与启动模拟服务器有什么关系。
我没有收到对我的问题的直接回答,但我确实找到了解决方法。与其使用 TestObserver 启动 WireMock 服务器,不如在测试中使用预操作。
为此,您需要为 UI 测试项目编辑方案:
- 单击
Test
旁边的披露箭头,然后单击 Pre-actions
- 点击
+
添加动作脚本
- 使用你选择的shell(我保持默认,
/bin/sh
)
- 在
Provide build settings from
下,选择您的测试目标
- 输入启动模拟服务器的脚本。
对于脚本,我使用了以下代码:
exec > /tmp/preaction-log.txt 2>&1
# Attempt to connect to an existing wiremock server, and exit if we succeed:
curl http://localhost:3000/__admin/mappings > /dev/null 2>&1 && exit 0 || echo "Attemmpting to spin up a Wiremock Server:"
# No existing server, so spin one up:
WIREMOCK_DIR=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}-Runner.app/Contents/PlugIns/${TARGET_NAME}.xctest/Contents/Resources/
/usr/bin/java -jar "${WIREMOCK_DIR}"wiremock-standalone-2.18.0.jar --port 3000 --root-dir "${WIREMOCK_PATH}" &
脚本的作用如下:
- 将所有输出记录到
/tmp/preaction-log.txt
,用于调试,因为操作前脚本不会记录到构建日志。
- 检查所需端口(在我们的示例中为 3000)上的 运行ning 服务器。我使用了 WireMockClient 使用的相同方法:尝试访问 "mappings" API。如果成功,我们将退出脚本。
- 如果我们到了这一步,我们可以假设我们需要启动服务器。所以我们这样做,使用一些 XCode 环境变量来指向我们在项目中存储服务器可执行文件的位置(如果您始终在系统上安装 WireMock 客户端,您可以将路径更改为您喜欢的任何路径) .
现在,只要您运行 一个测试用例,此脚本就会运行。我们仍然在 TestObserver 中的 运行 结束时关闭服务器。
我们正在使用一个独立的 wiremock 实例作为我们 Xcode UI 测试的模拟服务器。我们有一个测试观察者 class 负责启动此实例(如果需要)并在测试完成后将其拆除 运行。观察者的代码如下:
import AppKit
import XCTest
import WiremockClient
class SSUITestObserver: NSObject, XCTestObservation {
enum TestObserverError : Error {
case MockServerStartupError(String)
}
lazy var testBundleURL: URL = Bundle(for: SSUITestCase.self).bundleURL
lazy var testBundleBinURL: URL = self.testBundleURL.appendingPathComponent("..", isDirectory: true)
lazy var mockServerHomeURL: URL = self.testBundleURL.appendingPathComponent("Contents/Resources/", isDirectory: true)
lazy var mockServerJarURL: URL = self.mockServerHomeURL.appendingPathComponent("wiremock-standalone-2.18.0.jar", isDirectory: false)
override init() {
super.init()
NSLog("UI Test Observer Initialized")
XCTestObservationCenter.shared.addTestObserver(self)
}
func testBundleWillStart(_ testBundle: Bundle) {
NSLog("***Test Bundle starting")
do {
// Start the Wiremock server
try ensureMockServerIsRunning()
} catch {
fatalError("\n Failed during test bundle setup: \(error)\n")
}
}
public func testBundleDidFinish(_ testBundle: Bundle) {
NSLog("***Test Bundle completed")
stopMockServer()
}
func ensureMockServerIsRunning() throws {
WiremockClient.baseURL = SSUIIntegrationTestCase.mockServerAddress
guard !WiremockClient.isServerRunning() else { return }
let args = ["-jar",
self.mockServerJarURL.path,
"--port", "3000",
"--root-dir", self.mockServerHomeURL.path]
_ = Process.launchedProcess(launchPath: "/usr/bin/java", arguments: args)
for _ in 1...9 {
if WiremockClient.isServerRunning() { return }
sleep(1)
}
throw TestObserverError.MockServerStartupError("Error staring up the mock server instance!")
}
func stopMockServer() {
WiremockClient.shutdownServer()
}
func resetMockServerStubs() {
WiremockClient.reset()
}
}
在我迁移到 macOS 10.14 之前一切都很好。以前,我们没有对 UITest 目标进行代码签名。在移动到 10.14 后,运行ning 测试现在在测试甚至开始 运行 之前失败并出现 bootstrap 错误。我发现为测试打开自动代码签名可以解决这个问题。
然而,这会导致第二个问题:在上面的 launchedProcess
行中,启动 Wiremock 服务器的尝试将失败并显示 java.lang.RuntimeException: java.net.SocketException: Operation not permitted
。如果在我执行测试之前启动服务器(例如在命令行上),一切正常。
那么我怎样才能摆脱这个第 22 条军规呢?在 10.13 下一切正常。我不清楚代码签名与启动模拟服务器有什么关系。
我没有收到对我的问题的直接回答,但我确实找到了解决方法。与其使用 TestObserver 启动 WireMock 服务器,不如在测试中使用预操作。
为此,您需要为 UI 测试项目编辑方案:
- 单击
Test
旁边的披露箭头,然后单击Pre-actions
- 点击
+
添加动作脚本 - 使用你选择的shell(我保持默认,
/bin/sh
) - 在
Provide build settings from
下,选择您的测试目标 - 输入启动模拟服务器的脚本。
对于脚本,我使用了以下代码:
exec > /tmp/preaction-log.txt 2>&1
# Attempt to connect to an existing wiremock server, and exit if we succeed:
curl http://localhost:3000/__admin/mappings > /dev/null 2>&1 && exit 0 || echo "Attemmpting to spin up a Wiremock Server:"
# No existing server, so spin one up:
WIREMOCK_DIR=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}-Runner.app/Contents/PlugIns/${TARGET_NAME}.xctest/Contents/Resources/
/usr/bin/java -jar "${WIREMOCK_DIR}"wiremock-standalone-2.18.0.jar --port 3000 --root-dir "${WIREMOCK_PATH}" &
脚本的作用如下:
- 将所有输出记录到
/tmp/preaction-log.txt
,用于调试,因为操作前脚本不会记录到构建日志。 - 检查所需端口(在我们的示例中为 3000)上的 运行ning 服务器。我使用了 WireMockClient 使用的相同方法:尝试访问 "mappings" API。如果成功,我们将退出脚本。
- 如果我们到了这一步,我们可以假设我们需要启动服务器。所以我们这样做,使用一些 XCode 环境变量来指向我们在项目中存储服务器可执行文件的位置(如果您始终在系统上安装 WireMock 客户端,您可以将路径更改为您喜欢的任何路径) .
现在,只要您运行 一个测试用例,此脚本就会运行。我们仍然在 TestObserver 中的 运行 结束时关闭服务器。