-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Swift Testing support: ServeCommand did not shutdown before deinit #3236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Note that similar issue occurs on Vapor 5.
The only workaround seems to call shutdown manually at the end of each test, which is not ideal: @testable import App
import Testing
import Vapor
import XCTVapor
final class AppTests {
var app: Application
init() async throws {
self.app = await Application(.testing)
try await configure(app)
}
@Test
func helloWorld() async throws {
try await self.app.test(.GET, "hello", afterResponse: { res async in
#expect(res.status == .ok)
#expect(res.body.string == "Hello, world!")
})
try await app.shutdown()
}
} |
Yeah the @Test
func helloWorld() async throws {
withApp(/* whatever set up needed*/) { app in
try await self.app.test(.GET, "hello", afterResponse: { res async in
#expect(res.status == .ok)
#expect(res.body.string == "Hello, world!")
})
}
} This is the recommended way of supporting structured concurrency in Swift Testing. I suspect Vapor 5 will have some helpers for this which we might back port. |
This comment was marked as outdated.
This comment was marked as outdated.
Because tests run by default in parallel, I've been changing my implementation a bit: import App
import Lock
import Vapor
import XCTVapor
func withApp(_ block: @Sendable (Application) async throws -> Void) async throws {
try await AppActor.shared.run(block: block)
}
private actor AppActor {
static let shared = AppActor()
private let lock = AsyncLock()
func run(block: (Application) async throws -> Void) async throws {
await lock.lock()
let app = await Application(.testing)
do {
try await configure(app)
try await block(app)
try await app.shutdown()
} catch {
try? await app.shutdown()
lock.unlock()
throw error
}
lock.unlock()
}
} This is using the awesome https://github.com/mattmassicotte/Lock from @mattmassicotte ensuring that only one app is used at the same time, and others waits for the previous to be uninitialized before being resumed. |
Why not just use the In general, anything that touches a DB will need to be sequential - there isn't really any way around that. For tests that don't need a database (such as if you architect your app with the repository pattern) you should be able to run these in parallel without any issue with the |
Maybe I misunderstood the doc, but for me, serialized only applies on a Suite, meaning that you have to wrap your tests. See https://mastodon.social/@deanatoire/113177506464630372 |
You can apply the trait to an individual test but yes the easiest way is a |
Describe the issue
As of today, it seems hard to convert XCTest to Swift Testing as is, as the tearDown/deinit upgrade changes a lot the behavior!
Vapor version
4.105.2
Operating system and version
macOS 15
Swift version
Swift 6.0
Steps to reproduce
Convert the test example to Swift Testing:
Then run the tests
Outcome
Assertion failed: ServeCommand did not shutdown before deinit
Additional notes
Running on my M1 Pro Mac with no virtualization (Xcode 16 RC)
The text was updated successfully, but these errors were encountered: