New expectDeallocation API for Swift Testing and XCTest (3.2) - #19
Open
DanielCech wants to merge 2 commits into
Open
DanielCech wants to merge 2 commits into
DanielCech wants to merge 2 commits into
Conversation
- expectDeallocation(_:timeout:afterRelease:of:) checks any class instance with weak references, no DeallocTestable conformance needed - Leaks are reported at the test's call site in both frameworks - Lifecycles: none, loadView, present, push, custom; interaction while on screen - trackForDeallocation for XCTestCase and the .checksDeallocation trait - expectDeallocation(of:resolvedFrom:) for AsyncContainer dependencies - Tests for macOS and the iOS simulator, Swift Testing sample in the DI sample app - iOS package tests in CI, README and CHANGELOG Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Writing a dealloc test today means subclassing
DeallocTester, adding aDeallocTestableconformance for every tested class, creating an expectation and waiting for it. When something leaks, the failure points to a line inside the library rather than to your test. And it only works in XCTest, while new projects are moving to Swift Testing.This PR adds a much simpler way to write dealloc tests, borrowing the best ideas from similar tools (weak-reference checks, SpecLeaks-style lifecycles, test traits). Nothing existing changes:
DeallocTesterkeeps working exactly as before, so this can ship as 3.2.0.What it looks like
That's the whole test. When it leaks, the failure appears on that line of your test:
What's new
expectDeallocationcreates an object, runs its lifecycle, releases it and checks that it's gone.DeallocTestableconformance needed. It works with any class, because it uses plain weak references.timeout(2 s) otherwise.afterReleaselets you clear something that legitimately holds the object (like a cache) before the check.Lifecycles decide what happens to the object before it's released, because many leaks only show up once a screen loads or appears:
.none(default).loadViewviewDidLoad), UIKit and AppKit.present.push.custom { … }.presentand.pushalso take aninteractionclosure that runs while the screen is visible, e.g. to tap through the flow you suspect of leaking.trackForDeallocationbrings leak checks to ordinary unit tests: wrap your system under test, and it's checked when the test ends..checksDeallocationtrait to a test or a whole suite.Dependency injection:
expectDeallocation(of: APIManaging.self, resolvedFrom: container)resolves a dependency, releases the container's shared instances and checks it.Robustness
Tests
swift test): Swift Testing and XCTest tests for both products. They cover clean objects, retain cycles, failures reported at the caller's line, every lifecycle path, errors thrown during interaction,afterRelease, the trait (including suites, stored properties and parameterized tests), and the DI helper..loadViewand.pushtests run in the package. The.presenttests are skipped there with a stated reason, because modal presentation needs a host app.ExpectDeallocationTests.swiftinDeallocTestsAppSPMchecks the same screens with the new API in a real host app..presentworks, and the deliberateSecondViewControllerleak is caught on the test's line.Docs
DeallocTesteris documented as the scenario API.CHANGELOG.mdcovering 3.1 and 3.2.Not in this PR
DeallocTester(4.0).🤖 Generated with Claude Code