[shared_preferences_foundation] Migrate XCTest to Swift Testing#10766
[shared_preferences_foundation] Migrate XCTest to Swift Testing#10766auto-submit[bot] merged 5 commits intoflutter:mainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request successfully migrates the tests for shared_preferences_foundation from XCTest to the modern Swift Testing framework. The changes are well-executed, utilizing parameterized tests to reduce boilerplate and improving test robustness by avoiding force unwraps. The decision to serialize tests is a good catch for the non-thread-safe API. I have one minor suggestion to improve consistency.
packages/shared_preferences/shared_preferences_foundation/darwin/Tests/RunnerTests.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Xcode is expecting this directory:

macOS gets away with it because there's a (probably unnecessary) Info.plist in the equivalent directory:
https://github.com/flutter/packages/tree/fb3e9081ca58b1cb3e54b8bd471c57116a72585e/packages/shared_preferences/shared_preferences_foundation/example/macos/RunnerTests
| #endif | ||
|
|
||
| class RunnerTests: XCTestCase { | ||
| @Suite(.serialized) |
There was a problem hiding this comment.
Lots of test failures when these tests run in parallel. For example, there's no locking in the update methods like:
Should probably be migrated to actor?
Surprisingly I don't see any open issues that look related.
There was a problem hiding this comment.
Should probably be migrated to actor?
We now have toooo many options!
- Actor
- GCD
- the new Synchronization framework introduced last year
- Locks (
os_unfair_lockis likely the most performant)
There was a problem hiding this comment.
Worth adding a TODO to remove .serialized?
There was a problem hiding this comment.
Come to think of it, this isn't actually a bug. The defaults themselves are a threadsafe API, so if calling code, like these tests, are relying on another thread not mutating the defaults, then it would up to that calling code to handle it. I actually now think @Suite(.serialized) is correct. I'll add a comment.
There was a problem hiding this comment.
I was going to say something like this. My understanding when I wrote this code is that behavior is expected. I can see changing it though, if we wanted to make the plugin work that way instead.
There was a problem hiding this comment.
There's still a few pieces here that look a little thread unsafe, for example:
But it's way less dire than I made it out to be in the initial description. Sorry.
There was a problem hiding this comment.
Had me worried there for a second :)
There was a problem hiding this comment.
If there are others, I'd be happy to hear about them though. I'm always happy to learn from my mistakes.
| #endif | ||
|
|
||
| class RunnerTests: XCTestCase { | ||
| @Suite(.serialized) |
There was a problem hiding this comment.
Should probably be migrated to actor?
We now have toooo many options!
- Actor
- GCD
- the new Synchronization framework introduced last year
- Locks (
os_unfair_lockis likely the most performant)
| #endif | ||
|
|
||
| class RunnerTests: XCTestCase { | ||
| @Suite(.serialized) |
There was a problem hiding this comment.
Worth adding a TODO to remove .serialized?
c570175 to
ce0147f
Compare
flutter/packages@e37af11...1cb2148 2026-01-27 engine-flutter-autoroll@skia.org Roll Flutter from 7165649 to dfd92b7 (22 revisions) (flutter/packages#10914) 2026-01-27 magder@google.com [shared_preferences_foundation] Migrate XCTest to Swift Testing (flutter/packages#10766) 2026-01-27 magder@google.com [pigeon] Migrate XCTest to Swift Testing (flutter/packages#10905) 2026-01-27 engine-flutter-autoroll@skia.org Roll Flutter (stable) from 8b87286 to bd7a4a6 (6 revisions) (flutter/packages#10913) 2026-01-27 47866232+chunhtai@users.noreply.github.com [ci] Add post release label to sync_release_pr workflow (flutter/packages#10864) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#181608) flutter/packages@e37af11...1cb2148 2026-01-27 engine-flutter-autoroll@skia.org Roll Flutter from 7165649 to dfd92b7 (22 revisions) (flutter/packages#10914) 2026-01-27 magder@google.com [shared_preferences_foundation] Migrate XCTest to Swift Testing (flutter/packages#10766) 2026-01-27 magder@google.com [pigeon] Migrate XCTest to Swift Testing (flutter/packages#10905) 2026-01-27 engine-flutter-autoroll@skia.org Roll Flutter (stable) from 8b87286 to bd7a4a6 (6 revisions) (flutter/packages#10913) 2026-01-27 47866232+chunhtai@users.noreply.github.com [ci] Add post release label to sync_release_pr workflow (flutter/packages#10864) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Part of flutter/flutter#180787
Use parameterized tests instead of testing in a for loop. I had to make the tests serializable because this shared preferences API is very un-threadsafe, and running them in parallel has many test failures where values are stomping on each other.
Adding CHANGELOG override per #10761 (comment)
macOS tests
``` ◇ Test run started. ↳ Testing Library Version: 102 (arm64e-apple-macos13.0) ◇ Suite RunnerTests started. ◇ Test setAndGet(prefix:) started. ◇ Passing 1 argument prefix → "aPrefix" to setAndGet(prefix:) ◇ Passing 1 argument prefix → "" to setAndGet(prefix:) ✔ Test setAndGet(prefix:) passed after 0.001 seconds. ◇ Test getWithAllowList(prefix:) started. ◇ Passing 1 argument prefix → "aPrefix" to getWithAllowList(prefix:) ◇ Passing 1 argument prefix → "" to getWithAllowList(prefix:) ✔ Test getWithAllowList(prefix:) passed after 0.001 seconds. ◇ Test remove(prefix:) started. ◇ Passing 1 argument prefix → "aPrefix" to remove(prefix:) ◇ Passing 1 argument prefix → "" to remove(prefix:) ✔ Test remove(prefix:) passed after 0.030 seconds. ◇ Test clearWithNoAllowlist(prefix:) started. ◇ Passing 1 argument prefix → "aPrefix" to clearWithNoAllowlist(prefix:) ◇ Passing 1 argument prefix → "" to clearWithNoAllowlist(prefix:) ✔ Test clearWithNoAllowlist(prefix:) passed after 0.002 seconds. ◇ Test clearWithAllowlist(prefix:) started. ◇ Passing 1 argument prefix → "aPrefix" to clearWithAllowlist(prefix:) ◇ Passing 1 argument prefix → "" to clearWithAllowlist(prefix:) ✔ Test clearWithAllowlist(prefix:) passed after 0.001 seconds. ◇ Test asyncSetAndGet() started. ✔ Test asyncSetAndGet() passed after 0.001 seconds. ◇ Test asyncGetAll() started. ✔ Test asyncGetAll() passed after 0.001 seconds. ◇ Test asyncGetAllWithAndWithoutSuiteName() started. ✔ Test asyncGetAllWithAndWithoutSuiteName() passed after 0.001 seconds. ◇ Test asyncGetAllWithAllowList() started. ✔ Test asyncGetAllWithAllowList() passed after 0.001 seconds. ◇ Test asyncRemove() started. ✔ Test asyncRemove() passed after 0.001 seconds. ◇ Test asyncClearWithNoAllowlist() started. ✔ Test asyncClearWithNoAllowlist() passed after 0.001 seconds. ◇ Test asyncClearWithAllowlist() started. ✔ Test asyncClearWithAllowlist() passed after 0.001 seconds. ✔ Suite RunnerTests passed after 0.044 seconds. ✔ Test run with 12 tests passed after 0.044 seconds. ``` https://ci.chromium.org/ui/p/flutter/builders/try/Mac_arm64%20macos_platform_tests%20master%20-%20packages/26300/overviewiOS tests
``` Testing started Test suite 'RunnerTests' started on 'Clone 1 of Flutter-iPhone - Runner (85304)' Test case 'RunnerTests/setAndGet(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.003 seconds) Test case 'RunnerTests/setAndGet(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.002 seconds) Test case 'RunnerTests/getWithAllowList(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.000 seconds) Test case 'RunnerTests/getWithAllowList(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.000 seconds) Test case 'RunnerTests/remove(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.001 seconds) Test case 'RunnerTests/remove(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.001 seconds) Test case 'RunnerTests/clearWithNoAllowlist(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.003 seconds) Test case 'RunnerTests/clearWithNoAllowlist(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.013 seconds) Test case 'RunnerTests/clearWithAllowlist(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.000 seconds) Test case 'RunnerTests/clearWithAllowlist(prefix:)' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.000 seconds) Test case 'RunnerTests/asyncSetAndGet()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.001 seconds) Test case 'RunnerTests/asyncGetAll()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.000 seconds) Test case 'RunnerTests/asyncGetAllWithAndWithoutSuiteName()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.002 seconds) Test case 'RunnerTests/asyncGetAllWithAllowList()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.019 seconds) Test case 'RunnerTests/asyncRemove()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.001 seconds) Test case 'RunnerTests/asyncClearWithNoAllowlist()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.005 seconds) Test case 'RunnerTests/asyncClearWithAllowlist()' passed on 'Clone 1 of Flutter-iPhone - Runner (85304)' (0.002 seconds) Successfully ran iOS xctest for packages/shared_preferences/shared_preferences_foundation/example ``` https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8693085104608886001/+/u/Run_package_tests/native_test/stdout[shared_preferences]pubspec.yamlwith an appropriate new version according to the pub versioning philosophy, or I have commented below to indicate which version change exemption this PR falls under1.CHANGELOG.mdto add a description of the change, following repository CHANGELOG style, or I have commented below to indicate which CHANGELOG exemption this PR falls under1.///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2 ↩3