Quick 中文文档指南:从单元测试入门到行为驱动测试的完整实践手册

发布时间:2026/9/24 15:21:29

Quick 中文文档指南:从单元测试入门到行为驱动测试的完整实践手册 测试开发工具【免费下载链接】QuickThe Swift (and Objective-C) testing framework.项目地址https://gitcode.com/gh_mirrors/qu/Quick点击查看免费下载Quick 是一个用于 Swift 与 Objective-C 的行为驱动开发BDD测试框架。本文以本仓库 Documentation/zh-cn 的中文文档索引为骨架系统整理该文档集包含的全部 14 份指南涵盖单元测试方法论Arrange/Act/Assert、行为测试、Quick 语法例子与例子群、Nimble 断言、Xcode 工程配置、安装方式、Objective-C 兼容、测试替身与共享用例等主题。读完本文你可以从零开始为 Swift/Objective-C 项目搭建 Quick 测试环境写出行为驱动、可读性高、可复用的测试代码并掌握排错技巧。一、文档集总览快速定位你需要的指南中文文档索引 是整个 Quick 文档的中文入口共收录 14 份主题指南。每份指南围绕单一主题展开如果你对单元测试完全陌生建议按照索引列出的顺序从上往下阅读。指南主题适用场景在项目中添加测试Xcode 测试 Target 配置遇到构建测试的问题时编写高效的 XCTest 测试: ArrangeAct 和 Assert单元测试写法学习如何高效编写XCTestCase测试不要测试代码而应该测试行为行为测试 vs 脆性测试辨别好坏测试使用 Nimble 断言让测试更清晰Nimble 断言与失败信息更快定位用例错误原因用 Quick 例子和例子群组织测试describe/context/it语法编写更高效的 BDD 测试用例测试 OS X 和 iOS 应用UIKit/AppKit 测试测试UIViewController等使用测试替身进行测试Mock/Stub/Fake隔离依赖进行独立测试使用 Shared Assertion 来复用测试模板代码共享用例itBehavesLike复用重复测试代码配置 Quick 的行为QuickConfiguration全局beforeEach/afterEach等在 Objective-C 中使用 QuickObjC 兼容与宏冲突Objective-C 项目使用 Quick安装 QuickGit Submodules/CocoaPods/SPM在项目中添加 Quick安装 Quick 文件模板Xcode 文件模板提高编写 spec 的效率更多资料外部资源索引深入学习测试常见的问题排错指南遇到问题时查阅仓库根目录的 README.md 同样提供了英文文档入口与 Swift 版本兼容表可作为快速参考。二、先打好基础Arrange、Act 与 Assert 三部曲无论你使用 XCTest、Quick 还是其他测试框架《编写高效的 XCTest 测试》 都建议遵循同一个三步模式Arrange—— 安排好所有先决条件和输入Act—— 对要测试的对象或方法进行演绎执行被测行为Assert—— 对预测结果作出断言。假设有一个Banana类源码思想见仓库 Swift 示例 中it的闭包用法public class Banana { private var isPeeled false public func peel() { isPeeled true } public var isEdible: Bool { return isPeeled } }对应的测试class BananaTests: XCTestCase { func testPeel() { // Arrange: Create the banana well be peeling. let banana Banana() // Act: Peel the banana. banana.peel() // Assert: Verify that the banana is now edible. XCTAssertTrue(banana.isEdible) } }2.1 使用明确清晰的方法名好的测试方法名应该满足两点明确什么是被测试的对象明确什么时候测试应该通过、什么时候应该失败。例如把testPeel()改名为testPeel_makesTheBananaEdible()testPeel指明了正在被测试的是Banana.peel()方法makesTheBananaEdible指明了调用该方法后香蕉已被剥皮可食用。这样当测试失败时仅凭方法名就能判断是程序代码写错了还是业务需求变化需要更新测试。2.2 对条件进行测试假设有一个offer(banana:)函数根据香蕉是否可食用返回不同的提示文案。文档建议为每个if条件单独写一个测试。func testOffer_whenTheBananaIsPeeled_offersTheBanana() { let banana Banana() banana.peel() let message offer(banana) XCTAssertEqual(message, Hey, want a banana?) } func testOffer_whenTheBananaIsntPeeled_offersToPeelTheBanana() { let banana Banana() let message offer(banana) XCTAssertEqual(message, Hey, want me to peel this banana for you?) }如果其中一个条件不再满足或需要修改就能立刻知道哪个测试需要处理。2.3 用setUp()精简 Arrange用 helper 共享 Arrange把重复的初始化代码移入XCTestCase.setUp()每个测试开始时都会调用一次class OfferTests: XCTestCase { var banana: Banana! override func setUp() { super.setUp() banana Banana() } // ... }如果多处测试共享同一段 Arrange 逻辑还可以定义通用 helper 函数。文档同时提醒用通用函数定义那些不能被抽象、或不会保存状态的方法抽象的子类和可修改的状态会使测试难以阅读。三、不要测试代码而应该测试行为《不要测试代码而应该测试行为》 提出了两个核心概念行为测试Behavioral Testing验证应用程序做了什么脆性测试Brittle Testing即使应用程序行为不变只要内部代码变化就失败的测试。3.1 脆性测试示例假设GorillaDB是一个键值对香蕉数据库。一种写法是保存香蕉后检查数据库大小是否 1func testSave_savesTheBananaToTheDatabase() { let database GorillaDB() let originalSize database.size let banana Banana() database.save(banana: banana, key: test-banana) XCTAssertEqual(database.size, originalSize 1) }一旦GorillaDB为了加速读取而引入缓存database.size会随缓存增加这个测试就会失败——尽管存取行为本身完全正常。这就是脆性测试。3.2 行为测试的正确姿势行为测试的关键是准确定位你希望程序代码做什么保存香蕉的行为应该是之后可以取回香蕉而非数据库大小增加。func testSave_savesTheBananaToTheDatabase() { let database GorillaDB() let banana Banana() database.save(banana: banana, key: test-banana) // Assert: The bananas saved to and loaded from the database should be the same. XCTAssertEqual(database.load(key: test-banana), banana) }编写行为测试时应自问两个问题这段程序代码是用来做什么的我的测试只验证了行为吗它可能因为代码运行的其他原因而不通过吗四、用 Nimble 断言让测试更清晰《使用 Nimble 断言》 指出当代码不如预期运行时单元测试应该能反映出问题所在。4.1XCTAssertTrue的痛点对于筛选傻猴子的silliest(monkeys:)函数若使用XCTAssertTrue(contains(sillyMonkeys, kiki))失败时只返回XCTAssertTrue failed你无法得知预期为真的表达式为什么为假。手动补上返回信息可以缓解XCTAssertTrue(contains(sillyMonkeys, kiki), Expected sillyMonkeys to contain Kiki)但每次都要手写返回信息非常繁琐。4.2 Nimble 的自动失败信息改用 Nimble 后断言本身自带清晰的失败信息expect(sillyMonkeys).to(contain(kiki))失败时输出expected to contain Monkey(name: Kiki, sillines: ExtremelySilly), got [Monkey(name: Jane, silliness: VerySilly)]信息直接点明预期包含kiki实际只包含jane据此即可快速修复实现public func silliest(monkeys: [Monkey]) - [Monkey] { return monkeys.filter { $0.silliness .verySilly || $0.silliness .extremelySilly } }4.3 常用 Nimble 断言一览expect(1 1).to(equal(2)) expect(1.2).to(beCloseTo(1.1, within: 0.1)) expect(3) 2 expect(seahorse).to(contain(sea)) expect([Atlantic, Pacific]).toNot(contain(Mississippi)) expect(ocean.isClean).toEventually(beTruthy())Nimble 提供了很多种断言每种都带有清晰的返回信息无需每次手写。从源码看Quick 将 Nimble 作为配套断言框架内置在 Externals/Nimble 目录中。五、用 Quick 例子和例子群组织测试《用 Quick 例子和例子群组织测试》 是文档集的核心实战章节。Quick 使用特殊语法定义例子examples和例子群example groups其两大目的促使你使用具有描述性的测试名称极大简化 Arrange 步骤的测试代码。5.1 例子使用itit函数接收两个参数例子的名称和闭包作用类似 XCTest 中的测试方法class DolphinSpec: QuickSpec { override class func spec() { it(is friendly) { expect(Dolphin().isFriendly).to(beTruthy()) } it(is smart) { expect(Dolphin().isSmart).to(beTruthy()) } } }Objective-C 版本使用QuickSpecBegin/QuickSpecEnd宏import Quick; import Nimble; QuickSpecBegin(DolphinSpec) it(is friendly, ^{ expect(([[Dolphin new] isFriendly])).to(beTruthy()); }); it(is smart, ^{ expect(([[Dolphin new] isSmart])).to(beTruthy()); }); QuickSpecEnd例子的描述性语言可以是任意长度、任意字符——涵盖英语及其他语言的字符甚至可以是表情符号。从 DSL.swift 的源码可以看到it(_:file:line:closure:)会将闭包注册到World中并记录#file与#line用于失败定位。5.2 例子群describe与context例子群是按逻辑关系组织的例子群内可共享配置setup和卸载teardown代码。用describe描述类和方法class DolphinSpec: QuickSpec { override class func spec() { describe(a dolphin) { describe(its click) { it(is loud) { let click Dolphin().click() expect(click.isLoud).to(beTruthy()) } it(has a high frequency) { let click Dolphin().click() expect(click.hasHighFrequency).to(beTruthy()) } } } } }运行后Xcode 中会显示完整的分层描述名DolphinSpec.a_dolphin_its_click_is_loudDolphinSpec.a_dolphin_its_click_has_a_high_frequency5.3 用beforeEach/afterEach共享配置与卸载代码在例子群内beforeEach会在每个例子运行前执行afterEach在每个例子后执行。嵌套的例子群会形成调用链外层beforeEach先执行再执行内层beforeEach仓库 Tests/QuickTests/QuickTests/FunctionalTests 下的BeforeEachTests.swift、AfterEachTests.swift等测试文件即用于验证这一行为class DolphinSpec: QuickSpec { override class func spec() { describe(a dolphin) { var dolphin: Dolphin! beforeEach { dolphin Dolphin() } describe(its click) { var click: Click! beforeEach { click dolphin.click() } it(is loud) { expect(click.isLoud).to(beTruthy()) } it(has a high frequency) { expect(click.hasHighFrequency).to(beTruthy()) } } } } }5.4 用context指定条件的行为context严格来说是describe的同义表达但特意使用它能让代码更易理解——它用来描述在什么条件下的行为class DolphinSpec: QuickSpec { override class func spec() { describe(a dolphin) { var dolphin: Dolphin! beforeEach { dolphin Dolphin() } describe(its click) { context(when the dolphin is not near anything interesting) { it(is only emitted once) { expect(dolphin.click().count).to(equal(1)) } } context(when the dolphin is near something interesting) { beforeEach { let ship SunkenShip() Jamaica.dolphinCove.add(ship) Jamaica.dolphinCove.add(dolphin) } it(is emitted three times) { expect(dolphin.click().count).to(equal(3)) } } } } } }对比 XCTest 中冗长的测试方法名func testDolphin_click_whenTheDolphinIsNearSomethingInteresting_isEmittedThreeTimes() { // ... }Quick 的分层结构让每种情况更易阅读且能为每个例子群独立配置。5.5 临时禁用xdescribe/xcontext/xit通过添加前缀x即可禁用例子或例子群。被禁用的例子名称会随测试结果打印在控制台但闭包内代码不会运行xdescribe(its click) { /* ...none of the code in this closure will be run. */ } xcontext(when the dolphin is not near anything interesting) { /* ... */ } xit(is only emitted once) { /* ... */ }在 DSL.swift 中xdescribe/xcontext/xit会通过World将对应例子标记为 pending挂起状态。5.6 临时运行一部分例子fit/fdescribe/fcontext只运行一两个例子比运行整个测试快得多。使用fit可以只运行指定的例子使用fdescribe或fcontext把焦点放在整个例子群fit(is loud) { // ...only this focused example will be run. } it(has a high frequency) { // ...this example is not focused, and will not be run. } fcontext(when the dolphin is near something interesting) { // ...examples in this group are also focused, so theyll be run. }从 WorldDSL.swift 可以看出fdescribe/fcontext会为例子群打上.focused过滤标志Quick 在执行时只运行带焦点标志的例子其过滤逻辑在 Filter.swift 中实现。仓库 Tests/QuickTests/QuickFocusedTests 下的FocusedTests.swift与FacusedTestsAsync.swift专门验证了焦点例子的行为。5.7 全局配置beforeSuite/afterSuite某些配置需要在所有例子运行之前完成使用beforeSuite和afterSuiteclass DolphinSpec: QuickSpec { override class func spec() { beforeSuite { OceanDatabase.createDatabase(name: test.db) OceanDatabase.connectToDatabase(name: test.db) } afterSuite { OceanDatabase.teardownDatabase(name: test.db) } describe(a dolphin) { // ... } } }可以添加多个beforeSuite和afterSuite所有beforeSuite闭包都会在其它测试运行前执行所有afterSuite闭包都会在其它测试运行结束后执行但并不保证这些闭包按先后顺序执行DSL.swift 的源码注释明确说明了这一点。5.8 访问当前例子的元数据beforeEach和afterEach闭包可以接收元数据参数用于获取当前例子的名称、序号等信息beforeEach { exampleMetadata in print(Example number \(exampleMetadata.exampleIndex) is about to be run.) } afterEach { exampleMetadata in print(Example number \(exampleMetadata.exampleIndex) has run.) }Objective-C 中使用beforeEachWithMetadata/afterEachWithMetadata。元数据类型为ExampleMetadata定义于 Sources/Quick/Examples/ExampleMetadata.swift仓库测试 Tests/QuickTests/QuickTests/FunctionalTests/TestStateSpec.swift 覆盖了相关状态行为。六、配置 Quick 的行为《配置 Quick 的行为》 介绍如何自定义 Quick 的运行行为通过继承QuickConfiguration并重写QuickConfiguration.Type.configure()类方法import Quick class ProjectDataTestConfiguration: QuickConfiguration { override class func configure(configuration: QCKConfiguration) { // ...set options on the configuration object here. } }Objective-C 版本import Quick; QuickConfigurationBegin(ProjectDataTestConfiguration) (void)configure:(QCKConfiguration *configuration) { // ...set options on the configuration object here. } QuickConfigurationEnd一个项目可以包含多个配置类Quick不保证这些配置执行的先后顺序。6.1 添加全局beforeEach/afterEach通过配置对象可以为每个例子的运行前后注册全局闭包class FinConfiguration: QuickConfiguration { override class func configure(configuration: QCKConfiguration) { configuration.beforeEach { Dorsal.sharedFin().height 0 } } }也支持带元数据的版本以便在全局闭包中读取当前例子名称等信息class SeaConfiguration: QuickConfiguration { override class func configure(configuration: QCKConfiguration) { configuration.beforeEach { exampleMetadata in // ...use the example metadata object to access the current example name, and more. } } }从源码看配置的入口在 Sources/Quick/Configuration/QuickConfiguration.swift实际的beforeEach/afterEach全局钩子由 Sources/Quick/Hooks/SuiteHooks.swift 与 Sources/Quick/Hooks/ExampleHooks.swift 提供仓库测试 Tests/QuickTests/QuickTests/FunctionalTests/Configuration 目录下有对应验证用例。七、安装 Quick《安装 Quick》 提供了三种主要安装方式Git Submodules、CocoaPods、Swift Package Manager在文档写作时 SPM 标记为实验性。Quick 提供例子与例子群语法Nimble 提供expect(...).to断言语法二者可单独使用也可搭配使用。7.1 Git Submodulesgit submodule add gitgithub.com:Quick/Quick.git Vendor/Quick git submodule add gitgithub.com:Quick/Nimble.git Vendor/Nimble git submodule update --init --recursive随后在 Xcode 中完成以下步骤为项目新建.xcworkspace若已有则跳过把Quick.xcodeproj添加到 workspace把Nimble.xcodeproj添加到 workspace——它位于path/to/Quick/Externals/Nimble。从 Quick 的依赖库中添加 Nimble而非直接作为子模块可以确保无论所用 Quick 是什么版本都能使用正确版本的 Nimble把Quick.framework和Nimble.framework添加到测试目标 Build Phases 的 Link Binary with Libraries 列表注意区分 OS X 与 iOS 两个平台产物更新子模块在 Quick 目录执行git checkout main与git pull --rebase origin main然后git commit -m Updated Quick submodule他人克隆后运行git submodule update --init --recursive即可同步子模块。7.2 CocoaPods首先将 CocoaPods 升级到 0.36 或更高版本并在 Podfile 中添加use_frameworks!# Podfile use_frameworks! def testing_pods pod Quick pod Nimble end target MyTests do testing_pods end target MyUITests do testing_pods end然后执行pod install。针对旧版 Swift1.2/Xcode 6文档也给出了使用pod Quick, ~0.3.0与pod Nimble, ~1.0.0的兼容方案。7.3 Swift Package Manager随着 swift.org 开源Swift 有了官方包管理器Quick 也借此首次可在非 Apple 平台使用。当前仓库的 Package.swift 与 Packageswift-5.9.swift 即为 SwiftPM 清单文件。仓库根 README.md 给出了现代 SwiftPM 用法示例dependencies: [ .package(url: https://github.com/Quick/Quick.git, from: 7.0.0), .package(url: https://github.com/Quick/Nimble.git, from: 12.0.0), ],注意文档同时提醒不建议在真实 iOS 设备上直接运行 Quick 形式的代码若确需如此需把Quick.framework与Nimble.framework作为Embedded Binaries添加到测试目标所在的Host Application中。八、在项目中添加测试Xcode 工程配置《在项目中添加测试》 覆盖四种语言组合的工程配置。8.1 用 Swift 测试 Swift 项目代码在.xcodeproj中将 Defines Modules 设置为YES在单元测试中添加testable import YourAppModuleName——这会暴露所有public和internal默认访问级别符号给测试代码但private仍保持私有。import XCTest testable import MyModule class MyClassTests: XCTestCase { // ... }文档特别警告有些开发者提倡直接把 Swift 源文件添加进测试 target但这会导致难以诊断的隐蔽错误因此并不推荐。8.2 用 Swift 测试 Objective-C 代码给测试 target 添加 bridging header并在其中引入待测试的代码// MyAppTests-BridgingHeader.h #import MyClass.h8.3 用 Objective-C 测试 Swift 代码使用objc桥接 Swift 类与方法并在测试中引入模块的 Swift 头文件import XCTest; #import MyModule-Swift.h interface MyClassTests: XCTestCase // ... end8.4 用 Objective-C 测试 Objective-C 代码在测试 target 中直接引入待测试代码文件import XCTest; #import MyClass.h interface MyClassTests: XCTestCase // ... end8.5 为命令行项目设置测试 Target在项目窗格中添加一个 target选择 OS X Unit Testing Bundle编辑主 target 的 scheme选中 Test 条目单击 Info 下的 选择需要测试的 bundle。九、在 Objective-C 中使用 Quick《在 Objective-C 中使用 Quick》 指出两点注意事项。9.1 可选的速记语法与命名冲突Quick 框架在 Objective-C 中提供了it、itShouldBehaveLike宏以及context()、describe()函数。若你的测试项目定义了同名符号可通过禁用速记语法避免冲突——必须在import Quick;之前定义宏#define QUICK_DISABLE_SHORT_SYNTAX 1 import Quick; QuickSpecBegin(DolphinSpec) // ... QuickSpecEnd也可以在测试 target 的构建设置中定义该宏。9.2 测试目标至少需要一个 Swift 文件如果测试目标没有至少一个 Swift 文件Swift 标准库就不会链接到测试目标导致 Quick 无法编译测试运行后终止并报错*** Test session exited(82) without checking in. Executable cannot be loaded for some other reason, such as a problem with a library it depends on or a code signature/entitlements mismatch.解决方案是添加一个空的 Swift 文件// SwiftSpec.swift import Quick十、使用测试替身进行测试《使用模拟对象进行测试》 介绍测试替身Test Double的概念。当Car依赖Tire时Tire里的 bug 会导致CarTests失败即使Car本身没有错误此时难以定位问题。解决方法是使用替身对象如PerfectTire替代真实依赖。测试替身有以下几种类型模拟对象Mock用于从测试类中接收输出验证交互桩对象Stub用于为测试类提供输入伪对象Fake具有与原来类相似的行为。10.1 用 Mock 隔离网络请求假设应用通过DataProviderProtocol从互联网获取数据protocol DataProviderProtocol: class { func fetch(callback: (data: String) - Void) }ViewController在viewDidLoad()中调用fetch()。测试时创建一个 Mock 实现不发起真实网络请求class MockDataProvider: NSObject, DataProviderProtocol { var fetchCalled false func fetch(callback: (data: String) - Void) { fetchCalled true callback(data: foobar) } }然后验证viewController加载时确实调用了dataProvider.fetch()override class func spec() { describe(view controller) { it(fetch data with data provider) { let mockProvier MockDataProvider() let viewController UIStoryboard(name: Main, bundle: nil) .instantiateViewControllerWithIdentifier(ViewController) as! ViewController viewController.dataProvier mockProvier expect(mockProvier.fetchCalled).to(equal(false)) let _ viewController.view expect(mockProvier.fetchCalled).to(equal(true)) } } }使用 Mock 的收益测试运行更快、即使未联网也可测试、能对ViewController进行独立测试。十一、使用 Shared Examples 复用测试模板代码《使用 Shared Assertion 来复用测试模板代码》 介绍用共享用例shared examples在不同对象上复用同一套测试代码。假设Edible协议Mackerel和Cod都遵循它。先在QuickConfiguration中定义共享用例class EdibleSharedExamplesConfiguration: QuickConfiguration { override class func configure(_ configuration: Configuration) { sharedExamples(something edible) { (sharedExampleContext: escaping SharedExampleContext) in it(makes dolphins happy) { let dolphin Dolphin(happy: false) let edible sharedExampleContext()[edible] dolphin.eat(edible) expect(dolphin.isHappy).to(beTruthy()) } } } }然后在各个 Spec 中通过itBehavesLike引用class MackerelSpec: QuickSpec { override class func spec() { var mackerel: Mackerel! beforeEach { mackerel Mackerel() } itBehavesLike(something edible) { [edible: mackerel] } } } class CodSpec: QuickSpec { override class func spec() { var cod: Cod! beforeEach { cod Cod() } itBehavesLike(something edible) { [edible: cod] } } }要点共享用例可包含任意数量的it、context和describe代码块若不需要传递上下文Swift 中可直接使用无参闭包sharedExamples(everything under the sea) { ... }然后itBehavesLike(everything under the sea)Objective-C 中即使不使用也必须传入带QCKDSLSharedExampleContext参数的 block也可以使用fitBehavesLike单独测试某个共享用例。从源码看sharedExamples与itBehavesLike均定义于 DSL.swiftsharedExamples在 5.9 之后的版本中还可用类型安全的Behavior/AsyncBehavior替代见 Sources/Quick/Behavior.swift 与 Sources/Quick/Async/AsyncBehavior.swift。十二、测试 OS X 和 iOS 应用《测试 OS X 和 iOS 应用》 介绍测试UIViewController等类的额外技巧基础配置见 在项目中添加测试。12.1 触发UIViewController生命周期事件应用运行时 UIKit 会自动触发生命周期事件但测试时需要手动触发有三种方法访问viewController.view触发viewDidLoad()使用beginAppearanceTransition(_:animated:)/endAppearanceTransition()触发大多数生命周期事件直接调用viewDidLoad()、viewWillAppear()等方法。class BananaViewControllerSpec: QuickSpec { override class func spec() { var viewController: BananaViewController! beforeEach { viewController BananaViewController() } describe(.viewDidLoad()) { beforeEach { // Method #1: Access the view to trigger BananaViewController.viewDidLoad(). let _ viewController.view } it(sets the banana count label to zero) { expect(viewController.bananaCountLabel.text).to(equal(0)) } } describe(the view) { beforeEach { // Method #2: Triggers .viewDidLoad(), .viewWillAppear(), and .viewDidAppear() events. viewController.beginAppearanceTransition(true, animated: false) viewController.endAppearanceTransition() } // ... } describe(.viewWillDisappear()) { beforeEach { // Method #3: Directly call the lifecycle event. viewController.viewWillDisappear(false) } // ... } } }12.2 初始化故事板中定义的视图控制器先为视图控制器分配 Storyboard ID再在测试中初始化var viewController: BananaViewController! beforeEach { // 1. Instantiate the storyboard. By default, its name is Main.storyboard. let storyboard UIStoryboard(name: Main, bundle: nil) // 2. Use the storyboard to instantiate the view controller. viewController storyboard.instantiateViewControllerWithIdentifier( BananaViewControllerID) as! BananaViewController }12.3 触发 UIControl 事件如点击按钮通过sendActionsForControlEvents(_:)在代码中模拟按钮点击describe(the more bananas button) { it(increments the banana count label when tapped) { viewController.moreButton.sendActionsForControlEvents( UIControlEvents.TouchUpInside) expect(viewController.bananaCountLabel.text).to(equal(1)) } }十三、安装 Quick 文件模板与常见问题13.1 安装文件模板《安装 Quick 文件模板》 介绍两种安装方式AlcatrazXcode 包管理器在包管理器中搜索 Quick 即可安装Rakefile 手动安装克隆仓库后执行rake templates:install安装rake templates:uninstall卸载$ git clone gitgithub.com:Quick/Quick.git $ rake templates:install仓库中的模板文件位于 Quick Templates 目录包含 Quick Spec Class.xctemplate 与 Quick Configuration Class.xctemplate各含 Swift 与 Objective-C 版本。13.2 常见问题排错《常见的问题》 针对 No such module Quick 给出了三个步骤如果已运行pod install关闭并重新打开 Xcode workspace删除~/Library/Developer/Xcode/DerivedData整个目录其中包含ModuleCache在 Manage Schemes 对话框中勾选Quick、Nimble、Pods-ProjectnameTests然后重新编译CmdB。十四、更多资源《更多资料》 列出了 Quick Specs 的示例项目如 ReactiveCocoa、Archimedes、objective-git、Moya、SugarRecord 等以及 OS X/iOS 单元测试的补充资源Quality Coding 博客、OCMock、Nocilla HTTP stubbing、Pivotal Labs 的 Jasmine 自定义匹配器教程等。仓库内的英文版文档Documentation/en-us与日文版Documentation/ja、韩文版Documentation/ko-kr、葡萄牙文版Documentation/pt-br内容可互为对照。结语这份中文文档集从最基础的 Arrange/Act/Assert 测试方法学到行为测试的理念辨析再到 Quick 的 BDD 语法、Nimble 断言、Xcode 工程配置、三种安装方式、Objective-C 兼容、测试替身与共享用例构成了一个完整的 Swift/Objective-C 测试知识体系。结合仓库源码如 Sources/Quick/DSL/DSL.swift 中的 DSL 实现、Sources/Quick/World.swift 中的 World 状态管理与 Tests 目录下的大量功能测试你可以在实际项目中逐步实践这些模式写出清晰、可靠、可维护的测试代码。赞分享测试开发工具【免费下载链接】QuickThe Swift (and Objective-C) testing framework.项目地址https://gitcode.com/gh_mirrors/qu/Quick点击查看免费下载相关推荐如何快速部署Neural Collaborative Filtering完整Docker实战教程如何快速部署Neural Collaborative Filtering完整Docker实战教程 Neural Collaborative Filteringchess.js测试驱动开发从单元测试到集成测试的完整实践chess.js测试驱动开发从单元测试到集成测试的完整实践 chess.js是一个功能强大的TypeScript国际象棋库它采用了严格的测试驱动开发方法来确游戏开发Quick 官方文档导航Swift 与 Objective-C 行为驱动测试框架的完整指南Quick 官方文档导航Swift 与 Objective C 行为驱动测试框架的完整指南 Quick 是一个面向 Swift 与 Objective C 的测试开发工具上一篇Slurm-web让HPC集群管理变得简单高效的开源解决方案下一篇终极ComfyUI容器化部署指南从0到1搭建AI绘图工作站创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/24 15:21:29

ESP8266供电实战:从3.3V稳压到深度睡眠续航优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/24 17:36:42

【全宇宙恒等系统云端部署和跑起来】

这是全宇宙恒等系统云端部署和跑起来,和豆包对话工作的文字版,可以看下,也可以学习参考。之前的脑机部署和电磁波部署方式也可以进行升级,然后尝试不同的部署方式,我是用的模式A的部署方式。部署到了一款智能工控板的数…

2026/9/24 17:36:42

从零向 UE 5.3 渲染管线插入一个 Mesh Pass

从零向 UE 5.3 渲染管线插入一个 Mesh Pass 前言 这次实验会在 Base Pass 之后、光照之前,把选中的 Mesh 再画一遍。预期效果很简单:在 UStaticMeshComponent 的 Rendering 高级选项中勾选 bRenderCustomMeshPass,运行时模型会呈现红色。 上…

2026/9/24 17:36:42

`del`的核心功能是解除名称(name)与对象(object)之间的绑定关系

在Python编程中,del是一个常被初学者忽视但功能强大的语句。它不仅可以删除变量、列表元素、字典键值对,还能用于删除对象的属性甚至整个对象。深入理解del的工作机制,对于掌握Python内存管理、编写高效且安全的代码具有重要意义。 本报告将从…

2026/9/24 17:36:42

AI时代程序员效率跃迁:从返工少到快人一步

AI时代程序员效率提升完全指南:从小妙招到工具链本文整合了AI辅助开发技巧、程序员实用小妙招、高效工作方法和工具链推荐。核心观点只有一个:效率不是敲得快,而是返工少。适合所有想提升日常开发效率的程序员。一、先说个反直觉的事&#xf…

2026/9/23 12:07:00

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/24 0:00:21

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:21

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:21

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码