We are using a standalone wiremock instance as a mock server for our Xcode UI tests. We have an test observer class which is responsible for spinning up this instance (if required) and tearing it down upon completion of the test run. The code for the observer is as follows:
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()
}
}
All was well until I moved to macOS 10.14. Formerly, we were not code signing the UITest target. Upon moving to 10.14, running tests now fails with a bootstrap error before the tests even begin to run. I discovered that turning on automatic code-signing for on the tests gets around this problem.
However, this causes a second problem: on the launchedProcess
line above, the attempt to spin up the wiremock server will fail with java.lang.RuntimeException: java.net.SocketException: Operation not permitted
. If the server is launched (e.g. on the command line) before I execute the tests, everything works fine.
So how can I get myself out of this catch-22? Everything worked well under 10.13. It's unclear to me what code-signing has to do with launching a mock server.
I did not receive a direct answer to my question, but I did find a workaround. Rather than use a TestObserver to start the WireMock server, you can instead use a pre-action on the test.
To do this, you want to edit the scheme for your UI test project:
Test
, then click on Pre-actions
+
to add an action script/bin/sh
)Provide build settings from
, choose your test targetFor the script, I used the following code:
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}" &
Here's what the script does:
/tmp/preaction-log.txt
, for debugging, as pre-action scripts do not get logged to the build log.Now this script will run whenever you run a test case. We still shut down the server at the end of the run within our TestObserver.