Skip to content
Prepare to Grow

Swift Fundamentals

Testing and Debugging Swift Code

Verify behavior with focused tests and investigate failures systematically with Xcode debugging tools.

Beginner4 min read2 guided activities

Before you begin

What you will understand

  • Write small tests around observable behavior.
  • Use Arrange–Act–Assert to structure a test.
  • Investigate failures with breakpoints and the debugger.
  • Design Swift code that is easier to test.
01

Learning stage

Concept Explanation

A test provides repeatable evidence that code behaves as intended. Good unit tests choose one behavior, arrange a meaningful state, perform an action, and verify an observable result. Test outcomes and boundaries rather than private implementation details so the code can evolve without rewriting every test.

Debugging is a disciplined search for the first point where reality differs from expectation. Reproduce the issue, reduce it, form a hypothesis, inspect state with breakpoints or logs, and verify the fix with a test when possible. The compiler, debugger, console, call stack, and memory tools each answer different questions.

  • Arrange: create inputs and dependencies.
  • Act: perform one behavior.
  • Assert: compare the observable result with the expectation.
  • Breakpoint: pause execution and inspect variables and control flow.
  • Regression test: preserve the failure case after it is fixed.
02

Learning stage

Syntax & Examples

The pure function is easy to test because its result depends only on explicit inputs.

PriceCalculatorTests.swiftswift
import Testing

func finalPrice(subtotal: Double, discount: Double) -> Double {
  subtotal * (1 - discount)
}

@Test("A twenty-percent discount reduces the subtotal")
func appliesDiscount() {
  let result = finalPrice(subtotal: 100, discount: 0.20)
  #expect(result == 80)
}
The test names one behavior, supplies explicit inputs, and checks one observable result.
03

Learning stage

Real-World Usage

These concepts appear throughout production iOS code. Focus on the requirement each technique communicates.

  • Test model transformations, validation rules, and service behavior.
  • Add a regression test for a bug before or alongside its fix.
  • Use conditional breakpoints when a failure occurs only for one value.
  • Inspect the call stack to understand how execution reached an unexpected path.
04

Learning stage

Common Mistakes

Notice these mistakes early so the compiler and type system can help instead of becoming obstacles.

  • Testing private method calls instead of public behavior.
  • Combining many unrelated expectations in one test.
  • Using print statements as the only debugging strategy.
  • Changing code repeatedly without first reproducing and narrowing the issue.
  • Writing tests that depend on real time, network, or global state without control.
05

Learning stage

Practice Exercises

Work through these activities in a small Xcode project. No embedded playground is required on this site.

Activity 1

Test a validation rule

Write tests for valid, empty, and too-long usernames. Give each test a behavior-focused name.

Hint: Include boundary values, not only an average valid value.

Activity 2

Create a debugging plan

For a crash that happens only with an empty list, write the reproduction, hypothesis, breakpoint location, state to inspect, fix, and regression test.

Hint: Identify the earliest assumption that becomes false.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

What should a focused unit test verify?

  1. A.One observable behavior
  2. B.Every feature in the app
  3. C.Private implementation order
  4. D.A manual visual impression
Reveal answer

One observable behavior

Focused tests make failures easier to interpret and maintain.

QUESTION 2

What is the best first step when investigating a bug?

Reveal answer

Reproduce it reliably and record the expected versus actual behavior.

Without a reproduction, changes cannot be evaluated confidently.

07

Learning stage

Interview Preparation

Explain the idea in terms of its purpose, behavior, and tradeoffs rather than reciting syntax.

What makes Swift code easier to test?

Short answer: Explicit inputs, small responsibilities, controlled dependencies, and observable outputs.

Explore the detailed answer

Pure transformations are naturally testable. For stateful work, inject clocks, clients, or stores behind focused boundaries instead of reaching directly into global state. Tests should verify the public contract and use controlled alternatives for slow or unpredictable dependencies.

Possible follow-ups

  • • What is a regression test?
  • • When would you use an integration test instead?
08

Learning stage

Key Takeaways

Testing and debugging are complementary evidence-gathering skills. Write focused tests for contracts, reproduce failures before changing code, inspect state systematically, and preserve important fixes with regression coverage.

  • Test observable behavior and meaningful boundaries.
  • Arrange, act, and assert one focused scenario.
  • Reproduce and reduce before fixing.
  • Use breakpoints, call stacks, and controlled logs deliberately.
  • Turn fixed bugs into regression tests.