如何用Fox写出第一个属性测试:5步教程从排序用例到500个随机测试
如何用Fox写出第一个属性测试5步教程从排序用例到500个随机测试【免费下载链接】FoxProperty Based Testing Library for Objective-C and Swift. QuickCheck for Apples Platforms.项目地址: https://gitcode.com/gh_mirrors/fo/FoxFox 是一个面向 Objective-C 和 Swift 的属性测试Property Based Testing库可以理解为 Apple 平台上的 QuickCheck。本教程用一个「数字排序」用例带你 5 步写出第一个 Fox 属性测试让 Fox 自动生成数百个随机测试输入并在失败时自动收缩shrink到最小可复现用例。为什么要用属性测试传统的例子式测试只覆盖你手工写出的那几个输入而属性测试让 Fox 替你批量造数据对比项例子式测试Fox 属性测试测试输入手写几个固定值随机生成 500 组数据覆盖度依赖经验自动探索边界值、极端组合失败定位直接看到失败输入自动收缩为最小失败用例维护成本用例越堆越多一条性质描述长期有效一句话你描述排序结果必须有序这条性质Fox 负责用 500 个随机数组来验证它。第一步安装 Fox 到 Xcode 项目两种方式任选其一方式一CocoaPods推荐在测试 target 的 Podfile 中添加后执行pod installpod Fox, ~1.0.1方式二Git Submodule 手动集成git submodule add https://gitcode.com/gh_mirrors/fo/Fox Externals/Fox然后把Fox.xcodeproj拖入你的 Xcode 工程注意不是Fox.xcworkspace并将 Fox-iOS 或 Fox-OSX 链接到测试 target 即可。安装完成后的核心 API 都在Fox/Public/Fox.h中统一导出只需引入一个头文件。第二步先看一眼传统的排序例子测试假设你有一个MySorter工具类传统的 XCTest 写法是这样的- (void)testSort { NSArray *input [5, 2, 1]; NSArray *sortedNumbers [MySorter sortNumbers:input]; XCTAssertEqualObjects(sortedNumbers, [1, 2, 5]); }这条用例没问题但它只验证了[5, 2, 1]这一个输入。如果排序逻辑在元素个数 ≥ 5时才出错呢例子测试永远发现不了。第三步把它改写成 Fox 属性测试 ⚡改写思路来自教程docs/source/tutorial.rst把测试拆成三部分输入用生成器Generator描述而不是硬编码被测行为保持不变断言写成性质——任意输入下都应成立的逻辑完整代码如下- (void)testSortBySmallestNumber { // 输入随机生成任意长度的整数数组 idFOXGenerator arraysOfIntegers FOXArray(FOXInteger()); FOXAssert(FOXForAll(arraysOfIntegers, ^BOOL(NSArray *integers) { // 被测行为 NSArray *sortedNumbers [MySorter sortNumbers:integers]; // 性质断言排序后每个元素都不小于前一个 NSNumber *previousNumber nil; for (NSNumber *n in sortedNumbers) { if (!previousNumber || [previousNumber integerValue] [n integerValue]) { previousNumber n; } else { return NO; // 失败 } } return YES; // 成功 })); }这行测试可以读作对于所有整数数组排序后的结果都应是有序的。涉及到的四个核心 API 一览API作用源码位置FOXInteger()生成随机整数Fox/Public/Generators/FOXNumericGenerators.hFOXArray(...)生成可变长度的随机数组Fox/Public/Generators/FOXArrayGenerators.hFOXForAll(...)声明恒成立的性质Fox/Public/Generators/FOXPropertyGenerators.hFOXAssert(...)运行属性测试并断言Fox/Public/FOXDSL.h这些生成器都支持自动收缩比如生成整数失败时会自动尝试更小的值。第四步故意埋个 Bug看 Fox 如何缩小失败用例 现在给排序方法加一点恶意代码当元素个数 ≥ 5 时交换前两个元素。 (NSArray *)sortNumbers:(NSArray *)numbers { NSMutableArray *sortedNumbers [[numbers sortedArrayUsingSelector:selector(compare:)] mutableCopy]; if (sortedNumbers.count 5) { id tmp sortedNumbers[0]; sortedNumbers[0] sortedNumbers[1]; sortedNumbers[1] tmp; } return sortedNumbers; }再跑 Fox测试立刻失败但输出非常友好Property failed with: ( 0, 0, 0, 0, -1 )注意Fox 最初触发的失败用例可能是( -3, -3, 1, -2, -7, -5 )这样的一长串随机数但报告里直接给了收缩后的最小失败值——只有 5 个元素恰好踩中count 5的边界。这就是 shrink 的价值把随机数据里的噪音自动剥掉留下最容易复现、最容易定位的样例。原理上Fox 的生成器返回的是一棵玫瑰树Rose Tree每个节点是一个值子节点是更小的候选值。测试失败后Fox 会深度优先地遍历这棵树把 4 收缩为 0、50%、再减 1……直至找到最小失败值。整体数据管道如下图所示数据结构实现在Fox/Public/Data/FOXRoseTree.h与Fox/Private/Data/FOXConcreteSequence.m中。第五步跑满 500 个随机测试并配置生成参数 这是本教程标题的最后一环Fox 默认对每条属性断言生成 500 个随机测试无需任何配置。另外两个关键参数参数默认值含义numberOfTests500每条属性随机测试的轮数maximumSize200数据规模上限如FOXInteger生成 -200~200 的整数seed当前时间戳随机种子可用于复现失败想调整时把FOXAssert换成FOXAssertWithOptions定义见Fox/Public/FOXDSL.hFOXAssertWithOptions(FOXForAll(arraysOfIntegers, ^BOOL(NSArray *integers) { // ... 同上断言 ... }), (FOXOptions){ .seed 5, // 固定种子可复现失败 .numberOfTests 1000, // 默认 500 .maximumSize 100, // 默认 200 });也支持全局配置适合在整个测试 target 中统一生效FOXSetNumberOfTests(200); // 改为 200 轮加快反馈 FOXSetMaximumSize(50);或者通过环境变量FOX_SEED、FOX_NUM_TESTS、FOX_MAX_SIZE覆盖在 Xcode 中设置即可。配置优先级为单次断言 环境变量 setter 内置默认值详见docs/source/runner.rst。实用建议日常开发用numberOfTests 200左右快速反馈CI 上跑完整的 500 轮。进阶彩蛋用状态机测试有状态的 API除了纯函数Fox 还能测试队列、缓存这类有状态的 API——把每次 API 调用建模为状态机的一次转移Fox 就会生成合法的 API 调用序列来执行。例如测试队列的经典状态机模型核心 API 是FOXFiniteStateMachineFox/Public/Generators/FOXFiniteStateMachine.h和FOXExecuteCommands官方仓库自带完整示例FoxSpecs/Helpers/QueueAddTransition.m与FoxSpecs/Public/FOXFiniteStateMachineSpec.mm。小结 恭喜你完成第一个 Fox 属性测试回顾这 5 步安装CocoaPods 一行搞定或 git submodule 集成审视例子测试只覆盖手写输入改写FOXArray(FOXInteger())FOXForAllFOXAssert描述性质而非用例缩小失败时 Fox 自动收缩出最小复现用例定位 Bug 事半功倍规模化默认 500 个随机测试用FOXAssertWithOptions或环境变量调节强度正如 Dijkstra 所说程序测试至多证明错误存在而无法证明其不存在。 属性测试虽不能覆盖一切但 500 个随机用例加自动收缩已经比手写几个例子强太多了。接下来可以去Fox/Public/Generators/目录逛逛还有字典、字符串、集合等大量生成器等着你组合使用。【免费下载链接】FoxProperty Based Testing Library for Objective-C and Swift. QuickCheck for Apples Platforms.项目地址: https://gitcode.com/gh_mirrors/fo/Fox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考