用于 Swift 宏的魔法般的测试工具。
此库旨在支持为 Point-Free 制作的库和剧集,Point-Free 是一个由 Brandon Williams 和 Stephen Celis 主持的 Swift 编程语言探索视频系列。
您可以在此处观看所有剧集。
此库附带一个用于测试宏的工具,它比 SwiftSyntax 自带的默认工具更强大且更符合人体工程学。要使用该工具,只需指定您要扩展的宏以及使用该宏的 Swift 源代码字符串即可。
例如,要测试 SPM 宏模板附带的 #stringify
宏,只需编写以下内容
import MacroTesting
import XCTest
class StringifyTests: XCTestCase {
func testStringify() {
assertMacro(["stringify": StringifyMacro.self]) {
"""
#stringify(a + b)
"""
}
}
}
当您运行此测试时,该库将自动扩展源代码字符串中的宏,并将扩展写入测试文件
func testStringify() {
assertMacro(["stringify": StringifyMacro.self]) {
"""
#stringify(a + b)
"""
} expansion: {
"""
(a + b, "a + b")
"""
}
}
这就是全部。
如果将来宏的输出发生更改,例如向元组的参数添加标签,则再次运行测试将产生格式良好的消息
❌ 失败 - 实际输出 (+) 与预期输出 (−) 不同。差异:…
- (a + b, "a + b") + (result: a + b, code: "a + b")
您甚至可以通过向 assertMacro
提供 record
参数,让库自动将宏扩展重新记录到您的测试文件中
assertMacro(["stringify": StringifyMacro.self], record: .all) {
"""
#stringify(a + b)
"""
} expansion: {
"""
(a + b, "a + b")
"""
}
现在,当您再次运行测试时,最新的扩展宏将写入 expansion
尾随闭包。
如果您要为宏编写许多测试,则可以使用 XCTest 的 invokeTest
方法将每个测试与宏测试配置包装起来,从而避免在每个断言中重复指定宏的繁琐工作
class StringifyMacroTests: XCTestCase {
override func invokeTest() {
withMacroTesting(
macros: ["stringify": StringifyMacro.self]
) {
super.invokeTest()
}
}
func testStringify() {
assertMacro { // 👈 No need to specify the macros being tested
"""
#stringify(a + b)
"""
} expansion: {
"""
(a + b, "a + b")
"""
}
}
// ...
}
您可以将 record
参数传递给 withMacroTesting
,以重新记录测试用例(或套件,如果您使用自己的自定义基本测试用例类)中的每个断言
override func invokeTest() {
withMacroTesting(
record: .all
) {
super.invokeTest()
}
}
宏测试还可以测试诊断信息,例如警告、错误、注释和修复建议。当宏扩展发出诊断信息时,它将以内联方式呈现在测试中。例如,向异步函数添加完成处理程序函数的宏应用于非异步函数时,可能会发出错误和修复建议。生成的宏测试将完全捕获此信息,包括诊断信息的发出位置、修复建议的应用方式以及最终宏的扩展方式
func testNonAsyncFunctionDiagnostic() {
assertMacro {
"""
@AddCompletionHandler
func f(a: Int, for b: String) -> String {
return b
}
"""
} diagnostics: {
"""
@AddCompletionHandler
func f(a: Int, for b: String) -> String {
┬───
╰─ 🛑 can only add a completion-handler variant to an 'async' function
✏️ add 'async'
return b
}
"""
} fixes: {
"""
@AddCompletionHandler
func f(a: Int, for b: String) async -> String {
return b
}
"""
} expansion: {
"""
func f(a: Int, for b: String) async -> String {
return b
}
func f(a: Int, for b: String, completionHandler: @escaping (String) -> Void) {
Task {
completionHandler(await f(a: a, for: b, value))
}
}
"""
}
}
如果您正在使用 Swift 的内置 Testing 框架,则此库也支持它。您可以不只依赖 XCTest,还可以使用 swift-testing
提供的 Trait
系统配置您的测试。例如
import Testing
import MacroTesting
@Suite(
.macros(
record: .missing // Record only missing snapshots
macros: ["stringify": StringifyMacro.self],
)
)
struct StringifyMacroSwiftTestingTests {
@Test
func testStringify() {
assertMacro {
"""
#stringify(a + b)
"""
} expansion: {
"""
(a + b, "a + b")
"""
}
}
}
此外,macros
中的 record
参数可用于控制套件中所有测试的记录行为。此值也可以使用 SNAPSHOT_TESTING_RECORD
环境变量进行配置,以根据您的 CI 或本地环境动态调整记录行为。
此库的最新文档可在此处获取。
此库在 MIT 许可证下发布。有关详细信息,请参阅 LICENSE。