Hi,
Our team uses Xcode Cloud to run unit tests, and since around November, we’ve been frequently experiencing timeouts with the following type of process:
@Test func hogeTest() async {
// do something
hoge.do()
// wait until done
await wait(condition: { hoge.isDone })
// test result
#expect(hoge.isSucceeded)
}
private func wait(condition: () async -> Bool, timeout: TimeInterval = 0.5, pollingInterval: TimeInterval = 0.01) async throws {
let deadline = Date().addingTimeInterval(timeout)
while Date() < deadline {
if await condition() { return }
try await Task.sleep(nanoseconds: UInt64(round(pollingInterval * TimeInterval(NSEC_PER_SEC))))
}
Issue.record("timeout")
}
Although sleep is supposed to wait for only a few milliseconds, there are cases where it takes more than 10 seconds, leading to a timeout.
What could be causing this instability in the sleep duration? Additionally, if there are other recommended ways to implement polling and waiting in Swift Testing, I would appreciate it if you could share them.
A feedback report (FB15899163) has already been submitted.
Best regards,
Swift Testing
RSS for tagSwift Testing is a framework with expressive and intuitive APIs that make testing your Swift code a breeze.
Posts under Swift Testing tag
19 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hey guys.
I’m working on a project where I’m using the SwiftTesting framework instead of XCTest to run my unit tests. I have a file (test.png) located in my test resources folder:
PackageName > Tests > PackageNameTests > Resources > test.png
I’m trying to access this file in my tests, but I’m running into issues when trying to load it dynamically. Here’s what I’ve tried so far:
Using Bundle.module.path(forResource:ofType:): This approach didn’t work, as Bundle.module seems to be unsupported or returns nil in Swift Testing.
Using #file Macro for Relative Paths: I tried constructing a path based on #file and navigating to the resources directory, but it also didn’t yield the correct path.
Has anyone successfully loaded test resources in the Swift Testing framework? Is there a recommended way to access resource files in Swift Testing, especially for projects where Bundle.module isn’t available?
I've gone through the Apple Docs for Swift Testing, but I can't seem to find anything that answers my question.
Thanks in advance guys!
I have different versions of my iOS App (written in SwiftUI). The app on the store, the App Clip, and one or two next version apps not yet released (e.g. A/B comparison). All good. But now I've started creating UI and Unit tests and I'm confused about how to get this working.
Each build target has its own scheme. And in that scheme I have a Test plan for that target. E.g. The App Clip scheme has an App Clip test plan.
Since all the app variants are very similar, I only have one set of unit tests and one set of UI tests so each test plan includes the same unit test target and the UI test target.
Problem: When I selected a scheme (e.g. for the App Clip) and ran the tests, it turned out that all the tests ran for another build target, not the target of the scheme. I think this might be because within the definition of the test target there's a field specifying the host application. I.e. the build target.
Question: How can I set up my project so that the test plan uses the relevant target build?
Or do I have to duplicate all the test targets (one for each target)?
Or do I have to manually change each test target before running it for a particular build target?
Hi,
Considering this method I'd like to test:
public func play(_ soundFileName: String, shouldLoop: Bool) {
Task {
await dataSource.play(soundFileName, shouldLoop: shouldLoop)
}
}
Previously, with XCTest we could use an expectation and wait for it to be fulfilled:
func test()
sut.play("", shouldLoop: false)
wait(for: [mockedAudioPlayerDataSource.invokedPlayExpectation])
XCTAssertEqual(mockedAudioPlayerDataSource.invokedPlayCount, 1)
With Swift Testing, I am unsure what a unit test looks like.
Okay everyone who click into or just pass by this post ,to cut a farrrirly
long story short ,here is the thing...
I was devloping my app in the playground on my Mac , which was building for the iPad, In the early time of real machine commissioning(through the Xcode ),everything is okay everything is okay..
"well,mabe it's time to deploy my app to the playground in ipad"! Then,to top it all off🤣,then playground tell me
(In case that you can't understand chinese and creat ambiguity )
emm that's too tight...,so I can only got back to the Xcode changing my language version to swift 5
then.....
Noting change ....
and
I think err.. in order to properly deploy app to iPad
,I had to rework my code with swift 5!
So, I almost fell on my knees ,can somebody who in charge of the playground ,can somebody who in charge of the playground ,just ,just! shove swift 6 in the playground (as long as it make my code run anyway),
otherwise there's no way to debug it!
please please plase!
Hello Developers,
I regularly use Xcode Cloud to run unit tests, but since the release of Xcode 16, the testing process has become significantly slower.
I am seeking advice on how to improve the situation.
[ Details ]
With Xcode 15.4, unit tests took about 1 hour to complete.
However, since upgrading to Xcode 16, the tests have not finished even after 2 hours.
The blog post linked below also mentions significant overhead in running unit tests on Xcode Cloud, even with Xcode 15.4:
https://dwango.github.io/articles/2024-07_nicoiphone_xcode_cloud/#%E3%83%86%E3%82%B9%E3%83%88%E5%AE%9F%E8%A1%8C%E6%99%82%E9%96%93%E3%81%8C%E5%A2%97%E5%8A%A0%E3%81%97%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86%E5%95%8F%E9%A1%8C
According to the blog, while reviewing the xcodebuild-test-without-building.log, it was observed that the time from start to finish was about 4 minutes.
However, the overall “Run xcodebuild test-without-building” process took 23 minutes, with around 20 minutes of apparent idle time.
It seems that the idle time has increased even further with Xcode 16, resulting in more than twice the testing time.
[ Question/Request ]
Is there any way to reduce the overhead when running unit tests on Xcode Cloud, especially with the increased overhead in Xcode 16?
Any advice or solutions for improving the performance would be greatly appreciated.
Best regards,
I'm wondering if the tagging functionality which was added for Swift testing will be added to XCTest for UITests anytime soon.
Hi!
I have some unit tests which send and receive local notifications. Unfortunately, when ran on Xcode Cloud, the tests time out. I assume due to a call to requestAuthorization in init() (I have started using Swift Testing).
Is there a way to get around this issue in order to run the tests?
For my app I was trying to write some tests to ensure the functionality of all features. As I am using Xcode 16.0 I thought I might use Swift testing which was newly introduced and replaces XCTest.
I created a new test target with Swift Testing and tried to run the first test, which was created automatically by the system.
struct FinancialTests {
@Test func testExample() async throws {
#expect(true)
}
}
Xcode is also showing the test diamond next to the function so I clicked on it to execute it. The app started to build and the build ended successfully. The the next step was testing. And after waiting for 10 minutes or so, no test was executed. First I thought maybe the test was not found, but in the test case overview all tests were shown:
The run only shows this:
Can someone help me to get this running.
Many thanks!
Hello!
When running tests on iOS 17, the build succeeds but does not run on iOS 16. It consistently gets stuck on 'Testing'.
This issue does not occur on iOS 17.
I'm used to wait for expectations when using XCTest, but I'm completely stumped by the seemingly-absent option for expecting some parts of my code to be called in Swift Testing 🤔
Consider the following:
protocol MyAPI {
func getData() async throws -> String
}
class MockAPI: MyAPI {
let stub: () async throws -> String
init(stub: @escaping () async throws -> String = { "hello" }) {
self.stub = stub
}
func getData() async throws -> String {
try await stub()
}
}
Which is being used in my view model:
class MyViewModel: ObservableObject {
private let api: MyAPI
@Published
var data: String
init(api: MyAPI) {
self.api = api
}
func refresh() async throws {
self.data = try await api.getData()
}
}
When I wrote tests in the past, I would simply override the stub of the MockAPI implementation and fulfill an expectation in there:
class MyViewModelTests: XCTestCase {
func testModelCallsAPIOnRefresh() async throws {
let expectCallsAPI = expectation("Model should call API")
let api = MockAPI {
expectCallsAPI.fulfill()
return "hello"
}
let model = MyViewModel(api: api)
try await model.refresh()
await fulfillment(of: [expectCallsAPI], timeout: 1)
}
}
How would I go about checking that my model does indeed call the API when using Swift Testing?
Running Xcode 16b4 on Apple silicon.
Create a fresh Swift package, it will be using swift-tools-version: 6.0. Add a Swift Test to the test target with some basic assertion like #expect(true).
Run the test against the target My Mac and the test will compile, run and pass.
Run the test against the target My Mac (Mac Catalyst) and the test will compile and crash with EXC_BAD_ACCESS.
If you create an equivalent XCTest, it will compile, run and pass against both destinations.
Has anyone else experienced this? Is this already being tracked?
Is this possibly related? https://github.com/swiftlang/swift/pull/75432
With XCTest you were able to tun tests with:
MyTestCase.defaultTestSuite.run()
How can we use the new testing framework with Swift Playgrounds?
Does Swift Testing support using ‘any’ values as parameters like seen here for ‘any ChartDataPoint.Type’
@Test(arguments: [
(expectedBodyFatValues,
HKQuantityTypeIdentifier.bodyFatPercentage,
HKUnit.percent(),
BodyFatPoint.self),
(expectedActiveEnergyValues,
HKQuantityTypeIdentifier.activeEnergyBurned,
HKUnit.kilocalorie(),
ActiveCaloriesPoint.self),
(expectedBodyMassValues,
HKQuantityTypeIdentifier.bodyMass,
HKUnit.pound(),
BodyMassPoint.self),
(expectedBasalEnergyValues,
HKQuantityTypeIdentifier.basalEnergyBurned,
HKUnit.kilocalorie(),
BasalEnergyPoint.self)
])
func healthKitDataReading(
expectedData: [Double],
identifier: HKQuantityTypeIdentifier,
unit: HKUnit,
dataChartType: any ChartDataPoint.Type
) async throws {...}
Currently I can’t get this code to work, and see the error
… Conflicting arguments to generic parameter 'C' ('[([Double], HKQuantityTypeIdentifier, HKUnit, BodyFatPoint.Type)]' vs. '[([Double], HKQuantityTypeIdentifier, HKUnit, ActiveCaloriesPoint.Type)]' vs. '[([Double], HKQuantityTypeIdentifier, HKUnit, BodyMassPoint.Type)]' vs. '[([Double], HKQuantityTypeIdentifier, HKUnit, BasalEnergyPoint.Type)]')
Also, I can’t seem to use variables like ‘expectedBodyFatValues’ due to the error
Instance member 'expectedBodyFatValues' cannot be used on type 'Health_Mix_Swift_Tests'; did you mean to use a value of this type instead?
Only way I’ve found around this is including the entire array of values as the parameter, but it’s very cumbersome.
Why doesn’t deinit support async? At the end of a test, I want to wipe data from HealthKit, and it’s delete function is asynchronous.
From the Documentation of .timeLimit(_:):
Test timeouts do not support high-precision, arbitrarily short durations due to variability in testing environments. The time limit must be at least one minute, and can only be expressed in increments of one minute.
Unit Tests are usually considered too long when they take more than 0.1 seconds. So a minimal time limit of on minute is completely useless for unit tests.
Is there a similar trait in Swift Testing to handle millisecond time limits?
Hello everyone,
I’m encountering an issue with my Swift Testing suite where state changes made in one test method do not persist to another. I am using Swift’s @Suite and @Test annotations to group and serialize my tests, but it seems that the state is not being carried over between the tests. The second function fails with:
Expectation failed: (string → nil) != nil
Here is my example code:
import Testing
@Suite(.serialized)
struct createCheckTests {
var value = 25
var string: String? = nil
@Test("Create string")
mutating func stringCreation() {
#expect(value > 0)
string = "Value is: \(value)"
}
@Test("Check string")
func stringCheck() {
#expect(string != nil, "The string is nil")
print("\(String(describing: string))")
}
}
What is the correct way to approach such a scenario where I want to test two functions that are related, one to generate some value and one to check that generated value against it initial value using Suites to group and isolate them from other tests?
Thanks.
Is it a known issue that when attempting to test SwiftData objects with relationships in Swift Testing there are errors that do not occur when the app is running?
Example:
@Relationship(deleteRule: .cascade, inverse: \MBAccount.book) var accounts: [MBAccount] = []
and
@Relationship var book: Microbook?
Then the test:
let book = Microbook(name: "Julia's Cupcakes")
let account1 = MBAccount(name: "Chase Business Account")
let account2 = MBAccount(name: "Cash Drawer")
account1.book = book
account2.book = book
#expect(account1.name == "Chase Business Account")
#expect(account2.type == "asset")
}
Produces a fatal error while running test:
SwiftData/PersistentModel.swift:321: Fatal error: Unable to find relationship on MBAccount for KeyPath \MBAccount.book
Any ideas?
Currently Swift Testing has much less features than XCTest, so the adoption will be very slow from our side. Notable features we miss are UI tests, performance tests and attachments.
I did not want to create many issues in Swift Testing GitHub project as lots of these shortcoming are most probably tracked internally (I can see lots of references to radars in GitHub issues.)
So, my question is: Is it a good idea to wait with wider adoption or should we experiment with other tools like swift Benchmarks?