Skip to content

Add an experimental CustomTestReflectable protocol.#1594

Merged
grynspan merged 1 commit intomainfrom
jgrynspan/custom-test-reflectable
Feb 27, 2026
Merged

Add an experimental CustomTestReflectable protocol.#1594
grynspan merged 1 commit intomainfrom
jgrynspan/custom-test-reflectable

Conversation

@grynspan
Copy link
Contributor

This PR adds CustomTestReflectable as experimental SPI. This protocol can be used to customize the breakdown of a value shown when an expectation fails. For example, given this structure and test:

struct MyStruct {
  var x: Int
  func checkX(_ expected: Int) -> Bool { x == expected }
}

@Test func foo() {
  let value = MyStruct(x: 1234)
  #expect(value.checkX(6789))
}

A failure would currently be reported as:

<X>  Test "..." recorded an issue at [...]: Expectation failed: value.checkX(6789)
`->  value.checkX(6789) → false
`->    value → MyStruct(x: 1234)
`->      x → 1234

If we add a custom mirror to it, like so:

extension MyStruct: CustomTestReflectable {
  var customTestMirror: Mirror {
    Mirror(
      self,
      children: [
        (label: "x", value: x as Any),
        (label: "x is even?", value: x.isMultiple(of: 2)),
        (label: "x is positive?", value: x > 0),
      ]
    )
  }
}

Then the output becomes:

<X>  Test "..." recorded an issue at [...]: Expectation failed: value.checkX(6789)
`->  value.checkX(6789) → false
`->    value → MyStruct(x: 1234)
`->      x → 1234
`->      x is even? → true
`->      x is positive? → true

Checklist:

  • Code and documentation should follow the style of the Style Guide.
  • If public symbols are renamed or modified, DocC references should be updated.

This PR adds `CustomTestReflectable` as experimental SPI. This protocol can be
used to customize the breakdown of a value shown when an expectation fails. For
example, given this structure and test:

```swift
struct MyStruct {
  var x: Int
  func checkX(_ expected: Int) -> Bool { x == expected }
}

@test func foo() {
  let value = MyStruct(x: 1234)
  #expect(value.checkX(6789))
}
```

A failure would currently be reported as:

```
<X>  Test "..." recorded an issue at [...]: Expectation failed: value.checkX(6789)
`->  value.checkX(6789) → false
`->    value → MyStruct(x: 1234)
`->      x → 1234
````

If we add a custom mirror to it, like so:

```swift
extension MyStruct: CustomTestReflectable {
  var customTestMirror: Mirror {
    Mirror(
      self,
      children: [
        (label: "x", value: x as Any),
        (label: "x is even?", value: x.isMultiple(of: 2)),
        (label: "x is positive?", value: x > 0),
      ]
    )
  }
}
```

Then the output becomes:

```
<X>  Test "..." recorded an issue at [...]: Expectation failed: value.checkX(6789)
`->  value.checkX(6789) → false
`->    value → MyStruct(x: 1234)
`->      x → 1234
`->      x is even? → true
`->      x is positive? → true
```
@grynspan grynspan added this to the Swift 6.4.0 (main) milestone Feb 26, 2026
@grynspan grynspan self-assigned this Feb 26, 2026
@grynspan grynspan added the public-api Affects public API label Feb 26, 2026
@grynspan grynspan requested a review from briancroom as a code owner February 26, 2026 03:47
@grynspan grynspan added the issue-handling Related to Issue handling within the testing library label Feb 26, 2026
@grynspan grynspan added the command-line experience ⌨️ enhancements to the command line interface label Feb 26, 2026
@grynspan grynspan merged commit 6c301e0 into main Feb 27, 2026
26 checks passed
@grynspan grynspan deleted the jgrynspan/custom-test-reflectable branch February 27, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

command-line experience ⌨️ enhancements to the command line interface issue-handling Related to Issue handling within the testing library public-api Affects public API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants