WWDC26 identifies test framework interoperability and gradual migration as a dedicated topic in session 267, but that does not make a full rewrite the right move. The safest decision is to use Swift Testing first for new unit and business-logic integration tests, migrate existing XCTest tests according to maintenance frequency, and retain XCTest for UI automation, performance measurements, and some Objective-C exception cases. A remote CI pipeline should run both frameworks before stricter interoperability checks are enabled.
Suitable: new Swift tests, direct business-logic integration tests, and parameterized scenarios that benefit from modern Swift syntax.
Not suitable: a wholesale rewrite of a stable test suite when the rewrite would weaken regression coverage or make failures harder to diagnose.
00Who should use this migration guide?
This guide is for developers maintaining a large XCTest suite who are concerned that a rushed rewrite could damage an existing regression baseline.
It also helps developers starting a new testing system, and maintainers who run tests through a remote Mac, Swift Package Manager, or continuous integration and need consistent toolchain behavior.
Last updated September 2, 2026. Version-sensitive statements were checked against Apple’s Swift Testing documentation, the Xcode 27 Beta Release Notes, and Apple’s WWDC26 testing migration session. Xcode 27 behavior must still be treated as beta behavior until the relevant release status changes.
01Start with the test-type decision, not the file count
A migration plan based on “rewrite 80% of the test files” is usually weaker than one based on test responsibility. Each test should first be classified by the capability it needs.
| Test responsibility | Preferred framework in a new test | Existing test strategy | Reason to stop or retain |
|---|---|---|---|
| Pure unit testing | Swift Testing | Migrate when the test is actively changed | Assertions, traits, and parameterized cases can be expressed in Swift Testing |
| Business-logic integration testing | Swift Testing, when it does not require UI driving | Move gradually with the related code | Direct calls into application logic are a good migration boundary |
| UI automation | XCTest | Retain XCTest | The test needs UI interaction and system-level automation |
| Performance measurement | XCTest | Retain XCTest | Existing measurement workflows should not be replaced for syntax consistency |
| Objective-C exception coverage | Usually XCTest | Evaluate case by case | Some exception-oriented scenarios still depend on XCTest behavior |
| Swift Package tests | Swift Testing or XCTest, depending on toolchain | Verify with swift test and the project’s CI entry point |
Package execution and Xcode Test Plan behavior are not automatically identical |
| Mixed CI test bundle | Both frameworks | Run both, then tighten checks | Interoperability must be verified in the actual Scheme and Test Plan |
The central boundary is capability. Swift Testing is not merely a newer spelling for every XCTest feature, and XCTest is not automatically an obsolete dependency. Apple’s Xcode testing overview should be used to confirm which test types are supported by the selected Xcode release.
02Choose Swift Testing first for new application logic
A new project can establish its unit-test baseline with Swift Testing while keeping a separate XCTest UI Tests target. That arrangement avoids forcing UI automation into a framework that is being selected mainly for logic-level tests.
A minimal Swift Testing case can look like this:
import Testing
@testable import SampleApp
struct PricingTests {
@Test
func appliesTrialRule() {
let result = PricingService().price(for: .trial)
#expect(result == .free)
}
}
The project name, module name, and business values above are placeholders. They should be replaced with the project’s own names without exposing signing accounts, customer identifiers, repository paths, or CI secrets.
The migration value comes from the testing model rather than from shorter code alone:
@Testmakes test discovery explicit in Swift Testing.#expectrecords an evaluated condition and gives the failure more context than a generic assertion message.#requireis appropriate when later statements are meaningless without a valid prerequisite.- Traits can express conditions, tags, or execution metadata without scattering control logic through the test body.
- Parameterized tests can exercise several inputs through one test definition instead of creating many nearly identical methods.
The Swift Testing repository is the authoritative place to inspect the framework’s current implementation and usage model. It should not, however, be treated as proof that every Xcode 27 beta behavior is final.
Set a stopping condition before converting new tests
A new test should remain on XCTest when it needs a UI test target, performance measurement APIs, or a known Objective-C exception workflow. A project should not remove XCTest UI Tests simply to make every test use the same assertion syntax.
This rule also applies to integration tests. If an integration test directly creates services, repositories, or parsers and does not launch or drive the interface, Swift Testing is a reasonable default. If the test depends on a launched application, accessibility interaction, simulator state, or system UI, the test belongs to the XCTest track unless the project has verified an equivalent supported path.
03Migrate existing XCTest suites by maintenance frequency
For an established App, the right first unit is not a file. It is a test that is already being edited because its production behavior is changing.
Use this order:
- Tests being modified now: migrate these when the related feature changes, because the developer is already reviewing their expected behavior.
- Shared helpers used by active tests: inspect these next, since helper assumptions can affect both frameworks and create misleading failures.
- Frequently failing or frequently extended tests: migrate only after identifying whether the failure is a product defect, fixture defect, or framework-specific issue.
- Stable, rarely changed tests: leave them on XCTest until there is a concrete maintenance reason to touch them.
- UI, performance, and exceptional Objective-C cases: keep them on XCTest unless the project has verified an equivalent capability.
This approach answers the common question of where an existing XCTest project should begin: start with the tests closest to current product work, not with the largest directory or the oldest file.
Can both frameworks run in one test target?
A mixed test bundle can contain Swift Testing and XCTest tests, but the result must be verified through the exact project configuration. The relevant variables include the Xcode version, Scheme, Test Plan, test target membership, package dependencies, test discovery behavior, and the CI command used to launch the tests.
Apple’s XCTest migration documentation describes migration considerations, while the Xcode guide for adding tests provides the project-level setup context. Neither document should be generalized into a promise that every custom build arrangement behaves identically.
Before merging a converted test, compare its meaning with the original. The new test should preserve:
- the same input conditions and fixtures;
- the same expected product behavior;
- the same failure condition for the defect being guarded;
- the same skip or conditional-execution rule;
- an identifiable failure location in the test report.
A test that passes after migration but no longer exercises the original defect is not a successful migration. It is a coverage regression.
04Keep a deliberate XCTest track for system interaction
UI automation and performance testing are not inferior versions of unit testing. They answer different questions.
Swift Testing is a strong candidate for verifying calculations, state transitions, parsing, validation, dependency behavior, and direct service integration. XCTest remains the appropriate track when the test must interact with an application interface, measure performance using an established workflow, or cover a behavior tied to Objective-C exception handling.
The project should record this split in its Test Plan or test documentation rather than describing the retained XCTest tests as accidental leftovers. Apple’s guide on organizing tests for better feedback supports separating tests according to the feedback they provide.
Use this capability rule
- If the test calls business code directly and checks a result, choose Swift Testing first.
- If the test launches an application and performs interface actions, retain XCTest.
- If the test measures runtime or resource behavior through an XCTest performance workflow, retain XCTest.
- If the test depends on a documented Objective-C exception scenario, retain XCTest until an equivalent path is verified.
- If the test only uses XCTest assertions but has no UI, performance, or exception dependency, consider it for gradual migration.
- If the framework behavior is unclear in Xcode 27 beta, keep the existing test and create a small isolated verification case.
This is also the answer to whether Swift Testing can completely replace XCTest: not as a blanket migration policy. It may replace XCTest for suitable logic tests, but a project still needs XCTest where the required testing capability or validated execution path remains there.
05Evaluate Swift Package and cross-platform projects separately
Swift Package Manager introduces a different execution boundary from an Apple-platform App project. A package may run tests with swift test, while an App project may run through an Xcode Scheme and Test Plan. The fact that a test passes through one entry point does not establish that the same discovery, filtering, result reporting, or platform integration works through the other.
Cross-platform maintainers should divide tests into two groups:
- portable logic that can run on the platforms supported by the package and its dependencies;
- Apple-platform integration that requires macOS, Apple SDKs, simulator access, signing-related services, or Xcode-specific project configuration.
A Windows or Linux environment may be useful for early validation of portable Swift package logic when the package and toolchain support that workflow. It cannot replace macOS validation for Apple-platform integration, UI automation, simulator-dependent behavior, or an Xcode Test Plan.
The supported platform list and package behavior should be checked against the official Swift Testing documentation and the project’s actual package manifest. The maintainer should record both commands separately, for example:
swift test
xcodebuild test -scheme SanitizedScheme -testPlan SanitizedPlan
The commands are examples only. A real project must use its own Scheme and Test Plan names, and CI logs must not expose credentials or private paths.
06Validate the migration in remote CI before tightening checks
A remote Mac is useful when the local machine cannot run both test tracks consistently, but remote execution does not remove the need for reproducibility. It makes the execution contract more important.
Before changing the pipeline, fix the following inputs:
- the Xcode release or beta build;
- the Swift toolchain selected by the build environment;
- the Scheme and Test Plan;
- the simulator or device destination, if UI tests need one;
- the test command and result output path;
- the dependency resolution policy;
- the retention period and access method for
.xcresultbundles.
The official Xcode result interpretation guide should be used when deciding which result fields the pipeline records. The goal is not to claim a performance improvement without a controlled experiment. The goal is to prove that both frameworks were discovered, executed, and reported correctly.
Follow a five-stage acceptance run
- Freeze the baseline. Run the existing Test Plan without changing test source files. Save the test count, pass/fail state, skipped tests, and result bundle.
- Add one isolated Swift Testing case. Confirm that it is discovered by the intended Xcode entry point and appears in the expected result output.
- Run the mixed bundle. Execute Swift Testing unit tests beside XCTest unit and UI tests, then compare discovery and failure attribution with the baseline.
- Migrate one maintained test group. Reproduce a known failure or controlled assertion and verify that the migrated test still fails for the same reason.
- Test recovery. Disconnect or restart the remote session, reconnect, rerun the same Test Plan, and confirm that the unit-test and UI-test result files remain available through the agreed artifact path.
The acceptance record should answer concrete questions:
- Did the expected tests appear in discovery?
- Did skipped tests remain skipped for the same condition?
- Can a developer identify whether a failure came from Swift Testing or XCTest?
- Does a failing migrated test still detect the original defect?
- Is the
.xcresultartifact complete enough for later diagnosis? - Can the remote Mac repeat the run after a restart without manual repair?
A remote Mac used for this workflow should be treated as a test server, not as an interactive desktop that happens to run a test once. If a local Mac cannot keep the mixed regression suite available, a remote Mac environment from NUKCLOUD can be evaluated against the project’s actual Scheme, Test Plan, and artifact requirements rather than against a generic specification.
07Use a project-level migration checklist
The following checklist is designed for a pull request, release milestone, or CI environment review.
New project
- [ ] Swift Testing is the default for new unit tests.
- [ ] Direct business-logic integration tests have an explicit framework choice.
- [ ] XCTest UI Tests remain available when interface driving is required.
- [ ] Performance tests have not been rewritten merely for syntax consistency.
- [ ] A Test Plan identifies the intended test entry point.
- [ ] One mixed-framework run has been completed before the first release.
Existing project
- [ ] Tests are classified by behavior, not only by file count.
- [ ] Tests being actively modified receive migration priority.
- [ ] Shared helpers are reviewed before dependent tests are converted.
- [ ] Stable, rarely changed tests remain untouched unless there is a clear benefit.
- [ ] Migrated tests preserve fixtures, failure meaning, and skip behavior.
- [ ] UI, performance, and Objective-C exception cases have an explicit retain decision.
Remote CI or remote Mac
- [ ] Xcode and Swift toolchain inputs are fixed.
- [ ] The Scheme and Test Plan are version-controlled.
- [ ] Swift Testing and XCTest discovery has been verified together.
- [ ] Failure ownership is visible in the CI output.
- [ ]
.xcresultfiles are retained and retrievable. - [ ] A disconnect or restart recovery run has been completed.
- [ ] Xcode 27 beta assumptions are marked for review when RC or final behavior changes.
08Make the final choice by project type
A new Swift application with mostly pure logic should adopt Swift Testing early and retain XCTest for UI automation. A mature application with a stable XCTest suite should migrate only the tests that are being changed or that gain a clear maintenance benefit. A UI-heavy application should keep a substantial XCTest track. A Swift Package should validate portable tests through its package command and Apple integration through macOS and the project’s Xcode entry point.
The most defensible 2026 plan is therefore three lists: migrate, retain, and verify later. The “verify later” list is especially important for Xcode 27 beta behavior, mixed discovery, custom helpers, and package-to-Xcode differences. Apple’s official migration and release documentation should be rechecked when Xcode 27 reaches a later release stage; beta observations should not be presented as permanent defaults.
For teams currently relying on a local Mac, the alternative has real costs: the machine must remain available for long test runs, local storage and updates can interrupt the regression schedule, and a developer may lose the ability to reproduce the same Test Plan after a restart or configuration change. A remote Mac is not automatically better for every workload, especially when a project needs physical devices, local peripherals, or a stable high-volume environment for years. But for temporary capacity, distributed maintenance, and a repeatable remote CI test server, renting a Mac through NUKCLOUD’s available Mac options can be more flexible than buying a dedicated machine solely to keep Swift Testing and XCTest running side by side.
Before choosing the environment, the developer should write down the required Xcode version, Scheme, Test Plan, simulator needs, artifact policy, and restart recovery test. Those conditions determine whether a remote Mac is sufficient and which plan should be evaluated.