如何在 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 测试项目编辑方案:

  1. 单击 Test 旁边的披露箭头,然后单击 Pre-actions
  2. 点击+添加动作脚本
  3. 使用你选择的shell(我保持默认,/bin/sh
  4. Provide build settings from下,选择您的测试目标
  5. 输入启动模拟服务器的脚本。

对于脚本,我使用了以下代码:

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}" &

脚本的作用如下:

  1. 将所有输出记录到 /tmp/preaction-log.txt,用于调试,因为操作前脚本不会记录到构建日志。
  2. 检查所需端口(在我们的示例中为 3000)上的 运行ning 服务器。我使用了 WireMockClient 使用的相同方法:尝试访问 "mappings" API。如果成功,我们将退出脚本。
  3. 如果我们到了这一步,我们可以假设我们需要启动服务器。所以我们这样做,使用一些 XCode 环境变量来指向我们在项目中存储服务器可执行文件的位置(如果您始终在系统上安装 WireMock 客户端,您可以将路径更改为您喜欢的任何路径) .

现在,只要您运行 一个测试用例,此脚本就会运行。我们仍然在 TestObserver 中的 运行 结束时关闭服务器。