0Pricing
Swift Academy · Lesson

Testing and Debugging Macros

Writing unit tests for macro expansions using assertMacroExpansion.

Testing and Debugging Macros is a free Swift Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Test Macros?

Macros generate code at compile time. Unit tests verify the generated source before it reaches production.

// The swift-syntax package ships SwiftSyntaxMacrosTestSupport
// with assertMacroExpansion for testing macro output

assertMacroExpansion

assertMacroExpansion takes input source and expected expanded source and verifies they match.

import SwiftSyntaxMacrosTestSupport
import XCTest

final class StringifyMacroTests: XCTestCase {
  func testStringify() throws {
    assertMacroExpansion(
      "#stringify(1 + 2)",
      expandedSource: "(1 + 2, \"1 + 2\")",
      macros: ["stringify": StringifyMacro.self]
    )
  }
}

Testing Attached Macros

Provide the decorated struct/class as input and the fully expanded source as the expected output.

assertMacroExpansion(
  "@AddID struct User { var name: String }",
  expandedSource: """
  struct User {
    var name: String
    var id = UUID()
  }
  """,
  macros: ["AddID": AddIDMacro.self]
)

Testing Diagnostic Emission

Verify that your macro emits the correct diagnostic (warning/error) when misused.

assertMacroExpansion(
  "@AddID class Foo {}",
  expandedSource: "class Foo {}",
  diagnostics: [
    DiagnosticSpec(message: "@AddID can only be applied to structs", line: 1, column: 1)
  ],
  macros: ["AddID": AddIDMacro.self]
)

Expanding Macros in Xcode

In Xcode, right-click a macro invocation and select Expand Macro to inspect the generated code inline.

// Before expansion:
let (v, s) = #stringify(1 + 2)
// After:
let (v, s) = (1 + 2, "1 + 2")

Debugging with print in Macros

Use context.diagnose or print to stderr to debug macro logic during development.

// In macro implementation:
print("[StringifyMacro] expanding: \(node.description)", to: &standardError)

Breakpoints in Macro Tests

Because macros run in-process during tests, you can set Xcode breakpoints inside macro implementations during test runs.

// Set a breakpoint in StringifyMacro.expansion()
// Run the test target — breakpoints are hit

Syntax Tree Inspection

Use SwiftSyntax's .debugDescription to print the full syntax tree of an input node for debugging.

print(node.debugDescription)
// Prints the full SyntaxTree hierarchy

Testing Multiple Argument Variants

Write one test per distinct argument shape to ensure all code paths in the macro are exercised.

func testNoArgument() {
  assertMacroExpansion(
    "#stringify()",
    expandedSource: "#stringify()",
    diagnostics: [DiagnosticSpec(message: "Need an argument", line: 1, column: 1)],
    macros: ["stringify": StringifyMacro.self]
  )
}

Integration Testing

Add a test app target that actually uses the macro. Confirm compilation and runtime behaviour.

// In test app:
let (val, src) = #stringify(Date.now)
XCTAssertEqual(src, "Date.now")

CI for Macro Tests

Run macro tests in CI like any other Swift package: swift test in the package directory.

// CI command:
swift test --package-path MyMacros

Quick Check

Which function verifies that a macro expands to the expected source code in a unit test?

Lesson Recap

Test macros with assertMacroExpansion for correct output and DiagnosticSpec for error cases. Debug with Xcode expansion preview and in-process breakpoints during test runs. Run via swift test in CI.

Frequently asked questions

Is the “Testing and Debugging Macros” lesson free?

Yes — the full text of “Testing and Debugging Macros” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Testing and Debugging Macros”?

Writing unit tests for macro expansions using assertMacroExpansion. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Testing and Debugging Macros” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Macro Roles: Freestanding vs Attached
  2. Writing a Freestanding Expression Macro
  3. Attached Member Macros for Boilerplate Reduction
  4. Testing and Debugging Macros
← Back to Swift Academy