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 了解更多信息。