Skip to Content
Course content

200: Test Plans and Test Configurations

Click on the "Edit" button in the top corner of the screen to edit your slide content.

So, you've got a decent suite of tests now. But as your project grows, you're probably starting to feel the "Cmd+U drag." You hit that shortcut, go grab a coffee, and by the time you come back, the tests are done. It's a productivity killer. I've spent way too many hours waiting for a full suite to run just to verify a one-line change in a helper function.

The "Run Everything" Problem

Right now, we're likely using the default Xcode scheme. When you run tests, Xcode just grabs every single test target and runs every single test method. Let's look at our current setup for this WeatherApp project. We have WeatherParserTests (blazing fast), APIIntegrationTests (slow, hits the network), and WeatherUITests (glacial).

I tried running all of them this morning. It took nearly three minutes. Most of that time was spent waiting for the simulator to boot for the UI tests and waiting for the API to respond. I don't need to know if the UI is perfectly aligned every time I change a regex in the parser. I just want the parser tests to pass. I could manually disable targets in the Scheme editor, but that's tedious and doesn't scale if I'm working with a team.

Moving to a Test Plan

This is where Test Plans come in. Instead of the Scheme being the "source of truth" for what runs, we move that logic into a separate .xctestplan file. This lets us define different "flavors" of test runs.

I'll go to the Product > Scheme > Edit Scheme... menu, click on Test in the sidebar, and instead of "Use default test settings," I'll click the + button to create a new Test Plan. I'll call this FastCheck.xctestplan.

// In the Xcode UI for FastCheck.xctestplan:
// [x] WeatherParserTests
// [ ] APIIntegrationTests  <-- Uncheck this
// [ ] WeatherUITests       <-- Uncheck this

Now, when I select the "FastCheck" plan from the scheme dropdown and hit Cmd+U, it finishes in under two seconds. I've essentially created a "Smoke Test" suite. But wait—what happens when I actually do need to check the API? I don't want to keep clicking checkboxes. I'll just create a second plan called FullRegression.xctestplan and enable everything there. Now I have a toggle for "Dev mode" vs "CI mode."

Tuning the Environment

Here is where it gets interesting. Sometimes a test fails, but only in a weird, non-deterministic way. I suspect a race condition in our weather cache. I could turn on the Thread Sanitizer (TSan) for the whole project, but that slows down everything and might trigger false positives in third-party libraries.

I'll open a new plan called DebugConcurrency.xctestplan. Inside this plan, I can go to the Configurations tab. Instead of changing the global build settings, I'll specifically enable the Thread Sanitizer just for this plan.

  • Observation: I run the FullRegression plan. Everything passes.
  • Observation: I switch to the DebugConcurrency plan. Suddenly, the console screams about a data race in WeatherCache.swift.

The magic here is that I didn't have to change my project settings or rebuild the entire app from scratch with a different scheme. The test plan handles the environment configuration. I can even set specific Arguments Passed On Launch or environment variables (like -USE_MOCK_SERVER YES) for one plan without affecting the others.

Picking the Right Tool for the Job

If you're just starting a project, a single scheme is fine. But the moment you have tests that take more than 10 seconds, or tests that require different runtime environments (like a "Stress Test" plan that runs the same tests 100 times to find flakes), you need these plans. It stops the "test fatigue" where developers just stop running tests because they take too long.




📋 Practical Task

Exercise: Architecting a Multi-Tier Test Suite for a Currency Converter

You are working on a CurrencyConverter app. You have three test targets: ConversionLogicTests (Unit tests), ExchangeRateAPITests (Integration tests), and ConversionUITests (UI tests). Your goal is to set up a professional testing workflow using Test Plans.

  1. Create a new Test Plan named Developer.xctestplan. Configure it to only run ConversionLogicTests to ensure a near-instant feedback loop.
  2. Create a second Test Plan named Nightly.xctestplan. Configure it to run all three test targets.
  3. In the Nightly.xctestplan, navigate to the Configurations section and enable the Address Sanitizer to catch memory corruption issues that might only appear during long-running test suites.
  4. Add an Environment Variable to the Nightly.xctestplan called API_TIMEOUT with a value of 60, ensuring the integration tests don't fail prematurely on slow CI servers.
  5. Verify your setup by switching between the plans in the Xcode Scheme menu and observing which targets are executed in the Test Navigator.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.