Testing plays a crucial role in ensuring that applications remain robust, scalable, and high performing. As technology evolves, so must the tools we use to build and test digital products.
Enter Swift Testing, Apple’s new open-source testing framework designed to replace the decade-old XCTest framework. Swift Testing promises to modernise the testing process, delivering a more streamlined, user-friendly experience while providing developers with powerful new capabilities.
We fully embrace technological advancements that enable us to create exceptional products for our clients, it’s central to our company values: We Understand, We Care and We Never Stop Thinking.
In this Feature Focus, I explore the strengths and potential challenges of Swift Testing, offering actionable insights that can guide you in making the most of this new framework.
The Role of Testing in Product Development
Before going into the technical details of Swift Testing, it’s essential to understand the fundamental role of testing in digital product development. Testing ensures that the code we write behaves as expected, helping us catch bugs and identify issues early. More importantly, it allows us to deliver high-quality digital products that meet the needs of our users.
At Sonin, we adhere to Test-Driven Development (TDD), a methodology where we write tests before writing the actual code. This approach helps us to continuously verify that our code works as expected, even as it evolves over time. We run tests every time new code is added, and each time a new build is prepared for release. By doing so, we can spot regressions and bugs before they make their way into the final product.
A simple example of testing might be code that adds two numbers together. Instead of jumping straight to the solution, Test-Driven Development dictates that we first write a test. The test runs our code and compares its output to an expected value. For example, our test would input two numbers (3 + 4) and expect an output of 7. If the result of the code is not 7, the test fails, signalling an issue that needs to be addressed.
Introducing Swift Testing
For many years, XCTest has been the go-to framework for testing iOS applications. While it has served its purpose, XCTest was built in an era where Swift features were not as advanced as they are today. As Swift has evolved, developers have found themselves working around XCTest’s limitations, especially as new language capabilities emerged. With Swift Testing, Apple has introduced a tool designed specifically for modern Swift development. This tool not only addresses previous limitations but also makes the testing process more efficient and powerful.
Here are some key advantages that Swift Testing brings to the table:
1. Streamlined Test Scenarios
One of the most exciting features of Swift Testing is the ability to pass lists of test scenarios to a single test. For example, in our earlier case where we’re testing a function that adds two numbers, Swift Testing allows us to test multiple values at once. This is incredibly helpful when testing a range of numbers and significantly reduces the need for repetitive tests. It also enhances test coverage, ensuring that your code works across a variety of input scenarios.
In the screenshot below, we can see that the first test of 3 + 4 = 7 passed, but the following two tests failed. The likely cause? Our function may not be handling negative numbers correctly. The righthand code window shows that, in the case of 4 + -2, we expected an answer of 2, but the actual result was 6.

2. Enhanced Debugging Experience
Traditional testing frameworks often left developers scratching their heads when tests failed, especially when comparing objects for equality. In XCTest, if two objects don’t match, you’re left with a basic pass/fail result and must manually compare them, often in a text editor. Swift Testing solves this problem by clearly highlighting the differences between objects, making it easier and faster to identify issues. This improvement saves valuable time, especially in complex development scenarios where debugging can otherwise be time-consuming.
3. Customisable Traits
Swift Testing introduces the concept of Traits, which allows developers to add metadata to tests. For instance, at Sonin, we often use traits to attach bug ticket URLs to tests. This makes it easy to correlate failing tests with the corresponding issues in GitHub or our project management tools. Additionally, Traits enable developers to customise how tests are run – whether sequentially or in parallel, or even to disable specific tests when needed. This flexibility offers an extra layer of control, allowing teams to adapt the testing process to their specific workflows and project needs.
Swift Testing in Practice at Sonin
Since Apple’s release of Swift Testing in September 2024, we’ve integrated it into our testing practices at Sonin. For new tests, Swift Testing is our framework of choice. Its modern features, especially the ease with which we can write and manage tests, make it a valuable tool for enhancing our testing process.
However, while Swift Testing shows immense promise, it’s not without its challenges. As we move toward modern Swift paradigms, such as async/await, we find that some older testing practices still need to be maintained.

The Async/Await Challenge
One of the standout features of Swift Testing is its seamless handling of asynchronous code. Asynchronous code is essential when building modern apps, as it allows certain tasks – like waiting for data from an API or completing a lengthy computation – to pause and resume once those tasks are finished. Swift has made significant strides in how asynchronous code is handled in recent years, with the introduction of async/await simplifying the process and making it more intuitive.
While these updates are largely positive, there’s a noticeable trend in Apple’s documentation and developer resources: they often act as though the older way of handling asynchronous code doesn’t exist anymore. This creates a bit of a gap for developers who are working with legacy codebases that were written before the async/await paradigm became mainstream.
As a business we have embraced the new async/await approach and recognise its advantages, but we’re also conscious of the fact that many of our projects still contain legacy code that uses completion handlers—the older method for dealing with asynchronous tasks.
While Swift Testing handles async/await perfectly, there are some challenges when dealing with the older completion handler approach. In completion handler-based asynchronous code, developers specify blocks of code to execute once a certain task is complete. However, when testing such code, the test often ends before the completion handler has finished running, causing the test to fail or finish incorrectly.

What This Means for Swift Testing Adoption
For developers adopting Swift Testing, it’s important to understand that while it offers many advantages, it may not be suitable for every scenario. In some cases, it may still be better to use XCTest, especially when working with legacy codebases. Both frameworks are fully supported in Xcode (in fact, UI tests are only available in XCTest), and there’s no technical limitation to using both in the same project. At Sonin, we frequently run projects with hundreds of tests spread across both frameworks without issues. However, this does mean we forgo some of the newer features that Swift Testing provides, which is an unfortunate trade-off.
Apple has consistently maintained a forward-facing approach when it comes to development tools. This is evident in their developer content, which often showcases new features with modern examples, but doesn’t always address how to integrate these innovations into older code. This is especially true for macOS, a platform with a long legacy stretching back to the 1990s, rooted in NeXT and having undergone significant architectural and language shifts. The result is a substantial technical debt that Apple developers must navigate.
As developers working within Apple’s ecosystem, it’s vital to acknowledge the existence of this legacy code. While it’s tempting to jump straight into the latest language features, sometimes it’s wiser to step back and assess the impact of new technologies on existing systems. Swift Testing is undoubtedly a step forward but maintaining compatibility with legacy codebases is a balancing act, and adopting the newest tools might not always be the most practical approach for every project.
This is where a hybrid approach can be beneficial. As a team we often use XCTest alongside Swift Testing for projects that still rely on completion handlers. XCTest provides better support for this type of asynchronous code, while Swift Testing shines with newer, async/await-based systems.
Practical Advice for Developers
As we continue to incorporate Swift Testing into our workflow, here are a few actionable insights for teams looking to adopt this framework:
- Leverage Traits for Context: Attach meaningful metadata to your tests. This helps track the context behind each test case, particularly when working with large teams and complex projects.
- Transition Gradually: For legacy code, it’s often more practical to continue using XCTest, especially when dealing with completion handlers. Introduce Swift Testing for new features and codebases built with async/await to maximise the benefits of both frameworks.
- Stay Ahead of the Curve: Keep an eye on Apple’s updates to Swift Testing and async/await. As more APIs adopt the new asynchronous model, testing tools like Swift Testing will continue to evolve, offering even more powerful features for modern development. A good place to start is this article by Donny Wals about to how test Completion Handler code which I found really useful.
- Combine the Best of Both Worlds: There’s no need to choose one framework over the other. At Sonin, we use both XCTest and Swift Testing within the same projects, depending on the situation. This allows us to leverage the strengths of each framework while minimising any limitations.
Looking Ahead
Swift Testing is a significant step forward for iOS development, particularly in the realm of testing. It brings efficiency, flexibility, and clarity to the testing process, making it an invaluable tool for modern app development. However, as with any new technology, it’s important to evaluate how it fits within your existing codebase and workflows.
Sonin is committed to staying at the forefront of technology to deliver the best possible digital experiences. Swift Testing is just one example of how we integrate cutting-edge tools into our processes to help our clients achieve success. By combining our expertise in modern development practices with a deep understanding of legacy systems, we ensure that our clients receive stable, scalable, and innovative solutions.
Partnering with Sonin means gaining access to a team that is passionate about adopting new technologies and optimising existing workflows. We are committed to delivering high-quality, performant code that meets your business needs. Whether you’re building something new or maintaining an established product, we’ll guide you every step of the way. Let’s build the right product together.