Time is our most precious resource, as both humans and programmers.
An 8-hour workday contains 480 minutes. Out of the box, running a new iOS app's test suite from the terminal using xcodebuild test takes over 25 seconds on my M4 MacBook Pro. After extracting my application code into a Swift package—such that the application project itself contains virtually no code at all—running swift test against the same test suite now takes as little as 0.4 seconds. That's over 60 times faster.
Given 480 minutes, that's the difference between having a theoretical upper bound of 1152 potential actions per day and having 72,000.
If that number doesn't immediately mean anything to you, you're not alone. I've been harping on the importance of tightening this particular feedback loop my entire career. If you want to see the same point made with more charts and zeal, here's me saying the same shit a decade ago:
And yes, it's true that if you run tests through the Xcode GUI it's faster, but (1) that's no way to live, (2) it's still pretty damn slow, and (3) in a world where Claude Code exists and I want to constrain its shenanigans by running my tests in a hook, a 25-second turnaround time from the CLI is unacceptably slow.
Anyway, here's how I did it, so you can too.
The Starting Point
Here's what you get out-of-the-box after creating a new app with the latest OS 26 betas:
- A freshly-generated iOS 26 app (SwiftUI + SwiftData)
- A handful of boilerplate code listings and tests that the wizard creates
- Running tests via xcodebuild takes ~25 seconds minimum on my machine (add the UI tests and it runs well over a minute)
- Most of that time was Xcode performing code signing, spinning up simulators and doing... whatever Xcode does. Hell, it takes 1-3 seconds for the process to exit after it prints **TEST SUCCEEDED** for some fucking reason
- Want to pick up some speed by running a single Swift Testing function from the CLI? Well, if you want to do that you'll have to read this post to understand why that's impossible and then monkey-patch Apple's test runner
- Think you'll be clever and run swift test against your source code instead of xcodebuild? Well, you can't. It'll just bark at you that the test subcommand is only for Swift packages and not apps
This adds up to a situation in which test-driven development infeasible and using Claude Code unworkable. And this is a Hello World app! It's only going to get slower from here.
So—after consulting with some real iOS developers like Blake McAnally to confirm this isn't a really stupid idea—I went to work extracting the application code into a Swift package, for no other reason than to enable faster tests and better command-line ergonomics with swift test.
The Future State
It's frustrating as hell that something this stupid actually works:
- Create a Swift package as a framework for all your app's business logic, views, dependencies, everything
- Keep your app target as a thin shim that depends on the package as a framework and calls out to the root view from its entry point
- Test the package with swift test
- Test UI interactions with xcodebuild, presumably less often
This way, instead of firing up a simulator to run headless tests of Swift code, we're only doing so when we actually want to run a full build that includes UI tests.
Here's what the architecture now looks like:
I'm brand new to modern iOS development, so please tell me if I'm off my rocker here, but as far as I can tell, all this solution really does is introduce a minor Swift package configuration shim between the application project and the code itself, allowing it to be compiled and tested outside the context of my slow and girthy Xcode build.
The Implementation
Okay, now for some more detailed instructions you can follow along at home.
Step 1: Create the framework as a Swift Package
First, create a Swift Package alongside the Xcode project:
Step 2: Connect the framework to the app
If you don't already have a workspace, you'll need to create one to use both your app and framework together:
- Create a workspace file (if needed):
- In Xcode, open the workspace (not the project!)
- Add the framework as a dependency:
- Select the MyApp target → "General" → "Frameworks, Libraries, and Embedded Content"
- Click "+" and add MyAppCore
Now your app knows it depends on your "core" framework, so any builds will build it as well.
Step 3: Move everything to the framework
Move all your code and (non-UI) test listings from the app target to the newly-created Swift package
Before:
After:
Only the APIs your app actually references need to be made public. Internal types stay internal, and your tests can access them with @testable import.
Step 4: Expose the root view from the framework
The framework exposes a simple root view that the app can inject the SwiftData model container into and then attach to the window group:
Step 5: Slim Down the App
The app target is now an empty shell. All that's left is to add the package's root view to the application window group:
Step 6: Run your tests
If you fancy a single script/test file, you could do something like this to give yourself a convenient way to run just your unit tests:
Want fast feedback? Just run script/test unit. Want to run a single test? That's just script/test unit --filter testFunctionName
Step 7: Enjoy better output
Because Swift Testing is a modern tool, its output is actually reasonable. Meanwhile, xcodebuild barfs out an endless stream of gcc-lookin', PTSD-triggering nonsense.
Running swift test for a fresh Xcode project outputs this:
Not perfect, but at least comprehensible. Which is more than can be said of xcodebuild.
What's the catch?
When will this bite me in the ass? We'll find out. I'm told this will complicate static resource handling (e.g. images) a bit, and some Xcode features could get grumpy, but overall it sounds like there are a lot of teams doing essentially the same thing—they're just not necessarily blogging through it like I am.
Testing tools have never been Apple's forte, so all we can do is hope Apple leans into this transition and elevates swift test to the default way to run non-UI application tests before too long. Hopefully they also have plans to introduce a new project build tool for modern Swift apps that discards the legacy xcodebuild cruft.
What about you? Got your own hot Apple development tips? Let's hear'em.
Got a taste for hot, fresh takes?
Then you're in luck, because you'll pay $0 for my 2¢ when you subscribe to my work, whether via RSS or your favorite social network.
I also have a monthly newsletter where I write high-tempo, thought-provoking essays about life, in case that's more your speed:
And if you'd rather give your eyes a rest and your ears a workout, might I suggest my long-form solo podcast, Breaking Change? Odd are, you haven't heard anything quite like it.
.png)
