Why does my CI never finish and post a message to the merge request? Logged in to CI and oh, my merge job had been running for 23 minutes already, although typically it finishes in 4 minutes. What was going on? Nothing else than on unit-test marked with async was still waiting for an async function to finish. So what can we to avoid this? Let’s first create a Swift package which will be demonstrating the issue.
And a simple unit-test for the successful case.
This test passes after 100 seconds, but clearly, we do not want to wait so long if something takes way too much time. Instead, we want to fail the test when it is still running after 5 seconds.
Exploring XCTestCase executionTimeAllowance
XCTestCase has a property called executionTimeAllowance what we can set. Ideally I would like to write something like executionTimeAllowance = 5 and Xcode would fail the test with a timeout failure after 5 seconds.
But if we read the documentation, then it mentions that the value set to this property is rounded up to the nearest minute value. In addition, this value is not used if you do not enable it explicitly: “To use this setting, enable timeouts in your test plan or set the
-test-timeouts-enabled option to YES when using xcodebuild.”. If we are working on a Swift package, then I am actually not sure how to set it in the Package.swift so that it gets set when running the test from Xcode or from a command line.
Custom test execution with XCTestExpectation
One way to avoid never finishing tests is to use good old XCTestExpectation. We can set up a method which runs the async work and then waits for the test expectation with a timeout. If a timeout occurs, the test fails. If the async function throws an error, we can capture it, fail the test with XCTFail.
If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.