Skip to content

Commit 1d9ffbb

Browse files
Fix: Build the test view model lazily instead of in setUp
Supersedes the previous attempt on this file. MainActor.assumeIsolated was the wrong tool: its closure captures self, the XCTestCase, which is not Sendable, so sending it into a main-actor closure from a nonisolated override is itself a data race the compiler rejects. A lazy property needs no escape hatch. Its getter is main-actor because the class is, and XCTest creates a fresh test-case instance per test method, so each test still gets its own view model. tearDown only nilled the property, which per-test instances already handle.
1 parent b5ad67b commit 1d9ffbb

1 file changed

Lines changed: 4 additions & 18 deletions

File tree

‎CodeEditModules/Tests/CESourceControlTests/SourceControlViewModelTests.swift‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,10 @@ import XCTest
1010

1111
@MainActor
1212
final class SourceControlViewModelTests: XCTestCase {
13-
var viewModel: SourceControlViewModel!
14-
15-
// `setUp` and `tearDown` override nonisolated declarations on `XCTestCase`, so they stay
16-
// nonisolated even though this class is `@MainActor`. XCTest runs both on the main thread for
17-
// synchronous test cases, so state that here rather than weakening the isolation.
18-
override func setUp() {
19-
super.setUp()
20-
MainActor.assumeIsolated {
21-
viewModel = SourceControlViewModel()
22-
}
23-
}
24-
25-
override func tearDown() {
26-
MainActor.assumeIsolated {
27-
viewModel = nil
28-
}
29-
super.tearDown()
30-
}
13+
/// Built lazily rather than in `setUp`, which overrides a nonisolated `XCTestCase` method and so
14+
/// cannot touch this `@MainActor` class's state. XCTest creates a fresh test-case instance per
15+
/// test method, so each test still gets its own view model.
16+
private lazy var viewModel = SourceControlViewModel()
3117

3218
// MARK: - Operation field reset
3319

0 commit comments

Comments
 (0)