Approaches to testing macros

Hey everyone! I created MetaCodable to handle common Codable implementation generation use-cases. Currently the issue I face is better testability with the huge set of features this library supports, one of the thing I feel sorely lacking in macro testing approaches is asserting generated macro code compiles.

To address this I was thinking of creating snippets for each tests and grouping snippets based on test cases. Going through the Snippets pitch , I couldn't find any commands to run all the snippets or run snippets in parallel. Is running all the snippets possible with a single command?

What are the approaches you follow to test macro generated code compiles?

1 Like

In swift-mmio I include sample usages of the macros in a test target to ensure the expanded code type checks and compiles properly: swift-mmio/Tests/MMIOTests/ExpansionTypeCheckTests.swift at main · apple/swift-mmio · GitHub

Personally I find myself wanting to see @pointfree.co's macro testing support added to swift-syntax. I like that their library can autofill the expanded code which reduces the mechanical work needed for complex macros.

1 Like

Thanks @rauhul, but I wanted to exactly avoid the approach suggested as the seer amount of combinations supported by MetaCodable will require multiple different samples all with different names. This will also be difficult to maintain as the library scales with more features.

With the new Swift testing framework here is the approach I went with structuring tests:

struct TestCase {
    @Test
    func testErrorsWithMacro() {}

    struct MacroUseCase {
        struct Sample {}

        @Test
        func assertSampleExpansion() {}
    }
}
  • Here TestCase represents a specific macro/use-case scenario I am validating.

  • It can contain multiple testErrorsWithMacro which asserts proper diagnostic errors/warnings generated by the macro in invalid usages.

  • For each usage scenario of the macro one MacroUseCase type can be created.

    • It will contain a simple Sample representing the usage scenario, this will allow verification of any build errors.
    • It will contain one assertSampleExpansion that will assert the expanded code, allowing verification of the usage scenario.
    • Optionally additional tests can be added verifying the generated code behaves as expected.

We have found that a hybrid approach typically needs to be taken, as @rauhul mentioned. We will have a file that just lists out a bunch of usages of our macros to make sure that they at least compile, though there is no verification they are "correct". And then another file that uses our assertMacro helper to ensure that the expanded macro code looks correct.

I'm not sure if there is really much one can do to improve on this hybrid approach, but if there is I'd love to see it!

3 Likes

@mbrandonw I am not denying hybrid approach needs to be taken which is what I want to have as well. I have updated my answer with more details how it allows me improve upon the hybrid approach suggested.