PlaygroundTester
是一个软件包,使您能够向 iPad Swift Playgrounds 项目添加测试。
只需像往常一样将 PlaygroundTester
软件包添加到项目中即可。
为了让 PlaygroundTester
找到并正确执行测试,您的测试类需要:
TestCase
@objcMembers
@objc
目前,**不支持**从另一个测试类继承(因此您不能创建一个 class BaseTests: TestCase
,然后其他测试类从它继承)。
示例测试类声明
@objcMembers
final class MyTests: TestCase {
}
您可以覆盖四个方法来帮助设置和清理测试。
// Called once for the entire test class, before any tests are run.
open class func setUp() { }
// Called before each test method.
// If this method throws, the test method won't be executed, but `tearDown` will be.
open func setUp() throws { }
// Called after each test method.
open func tearDown() throws { }
// Called once for the entire test class, after all tests are run.
open class func tearDown() { }
}
为了让 PlaygroundTester
发现您的测试方法并自动运行它们,它们必须:
private
(即 public
或 internal
)test
开头任何 private
方法或不以 test
开头的方法都不会被自动执行,因此您可以利用这个机会来定义辅助方法。
示例方法定义
func testSample() { }
// Methods that won't be run automaticaly
private func testPrivateSample() { }
func helperMethod() { }
PlaygroundTester
支持抛出异常的测试方法 - 只需按照上述规则定义您的方法,并在其定义中添加 throws
。 PlaygroundTester
将捕获抛出的错误并报告它。
抛出异常的测试方法的示例定义
func testSampleThrowing() throws { }
目前,有一组基本的断言方法可用,它们模仿了 XCTest
的断言风格
// Assert of a passed boolean value is `true`/`false`
public func Assert(_ value: Bool, message: String = "")
public func AssertFalse(_ value: Bool, message: String = "")
// Assert if two passed values are equal / not equal.
public func AssertEqual<T: Equatable>(_ value: T, other: T, message: String = "")
public func AssertNotEqual<T: Equatable>(_ value: T, other: T, message: String = "")
// assert if passed optional value is `nil` / not `nil`.
public func AssertNil<T>(_ value: T?, message: String = "")
public func AssertNotNil<T>(_ value: T?, message: String = "")
与 XCTAssert
方法系列实现对等还有一些方法缺失,这些方法将在稍后添加。
PlaygroundTester
提供了一个类似于 XCTUnwrap
的方法
// Return an unwrapped value, or throw an error if `nil` was passed.
public func AssertUnwrap<T>(_ value: T?, message: String = "") throws -> T
您应该用 throws
标记您的测试方法,以避免需要自己处理这个抛出的错误。
带有 AssertUnwrap
的示例方法
func testSampleAssertUnwrap() throws {
let sampleArray = ["first", "second"]
let firstValue = try XCTUnwrap(sampleArray.first, "Array should have a first element").
// `firstValue` is non-optional here
}
PlaygroundTester
支持等待期望来测试异步代码。 期望可以使用 3 个属性进行配置:
expectedFulfilmentCount (默认 == 1)
- 期望应该被满足多少次才被认为是已满足。 如果期望被过度满足,将会失败。inverted (默认 == false)
- 如果期望是 inverted
,则如果它被满足,将会失败。inverted
期望,且 expectedFulfilmentCount > 1
,那么如果它被满足的次数少于 expectedFulfilmentCount
,则会被认为是已满足。您可以使用 AssertExpectations
方法来等待创建的期望
// Will wait for `timeout` seconds for `expectations` to be fulfilled before continuing test execution.
public func AssertExpectations(_ expectations: [Expectation], timeout: TimeInterval)
带有期望的示例测试
func testSampleExpectation() {
let expectation = Expectation(name: "Wait for main thread")
DispatchQueue.main.async {
expectation.fulfill()
}
AssertExpectations([expectation], timeout: 2)
}
目前,未等待的期望不会触发断言失败。
为了执行您的测试,您需要做的最后一件事是:将您的视图包装在 PlaygroundTesterWrapperView 中,并将 PlaygroundTester.PlaygroundTesterConfiguration.isTesting 标志设置为 true。在您的 App
对象中,只需这样做:
struct Myapp: App {
init() {
PlaygroundTester.PlaygroundTesterConfiguration.isTesting = true
}
var body: some Scene {
WindowGroup {
PlaygroundTester.PlaygroundTesterWrapperView {
// YourContentView()
}
}
}
}
之后,当以全屏或预览模式运行应用程序时,将改为发现并运行您的测试。
测试运行后,您可以导航它们以检查其结果并查看哪些断言失败。
Swift Playgrounds 目前不支持多个目标,因此您的测试文件需要与常规应用程序代码一起保存。 该软件包本身在其代码周围具有编译保护,因此在创建发布版本时,大部分代码将从您的生产应用程序中省略。 剩下的是对象和函数定义的最小集合,以便您的代码可以很好地编译,并且对 PlaygroundTester
提供的对象/函数的所有调用都基本上解析为 no-ops。
如果您还想从发布版本中删除您的测试,您需要在您的应用程序中添加一个编译标志。
现在,您需要按照以下步骤将编译标志添加到您的项目中:
Package.swift
文件.executableTarget
定义。swiftSettings: [.define("TESTING_ENABLED", .when(configuration: .debug))]
最后,目标定义应类似于这样:
targets: [
.executableTarget(
name: "AppModule",
dependencies: [
// if any
],
path: ".",
swiftSettings: [.define("TESTING_ENABLED", .when(configuration: .debug))]
)
]
您当然可以为该标志选择任何名称。
注意:我希望在 修补 Package.swift 中自动化此过程
setUp
/tearDown
方法我想探索并添加到 PlaygroundTester
的事项(随机顺序)
Package.swift
修补XCTest
的断言对等async
/await
的支持Combine
的支持请查看 Issues 了解更多信息。