基于属性的测试在Swift中:捕获你未曾寻找的Bug

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

基于属性的测试在Swift中:当常规测试失效时



您是否曾经编写过一个完美通过的单元测试,但应用程序却在真实数据上崩溃了?很熟悉,对吧?经典的基于示例的测试(当我们检查特定的输入和输出时)很好,但它们有一个根本性的缺陷:它们只检查我们自己想到的情况。但如果Bug存在于有效值的边界上,或者存在于我们根本没有想到的组合中呢?



这时,基于属性的测试在Swift中就登场了。这是一种方法,您不是描述具体的用例,而是描述属性(property),这些属性对于任何输入数据都必须为真。而一个专门的框架(例如SwiftCheck)会生成数百个随机值,并检查您的属性是否被违反。如果发现Bug,框架会“最小化”输入数据——您就能得到导致问题的最简单示例。



在本文中,我们将探讨如何将基于属性的测试Swift集成到您的项目中,编写真实的代码示例,并看看这种方法能捕获哪些Bug。我们开始吧!



什么是基于属性的测试,为什么需要它?



想象一下,您正在测试一个对数组进行排序的函数。与其编写10个不同数组的测试,您可以说:“对于任何数组,排序后长度不变,并且每个元素都小于或等于下一个元素”。这就是属性——一个必须成立的不变量。



基于属性的测试在Swift中非常适合用于:

  • 检查数学函数(加法、除法、四舍五入);
  • 测试解析器和序列化器(序列化 → 反序列化应返回原始数据);
  • 检查具有大量组合的业务逻辑;
  • 在边界值上寻找回归问题。


主要好处是:您能发现甚至未曾怀疑过的Bug。您得承认,这比确认显而易见的事情要酷得多。



SwiftCheck——Swift中基于属性测试的主要工具



在Swift世界中,这种方法最流行的框架是SwiftCheck。它移植了Haskell(QuickCheck库)的思想,并与XCTest完美集成。



要开始使用,请在Package.swift中添加依赖项:



// swift-tools-version:5.9import PackageDescription

let package = Package( name: "MyProject", dependencies: [ .package(url: "https://github.com/typelift/SwiftCheck.git", from: "0.12.0") ], targets: [ .testTarget( name: "MyProjectTests", dependencies: ["SwiftCheck"]), ])


现在可以编写测试了。让我们来看看基本语法。



第一个基于属性的测试:检查加法



让我们编写一个简单的属性:“加法是可结合的”。对于任何整数,a + b + c 应该等于 (a + b) + c。



import XCTestimport SwiftCheck

class MathPropertiesTests: XCTestCase { func testAdditionIsAssociative() { property("加法是可结合的") <- forAll { (a: Int, b: Int, c: Int) in return (a + b) + c == a + (b + c) } }}


运行测试——它会运行100个随机组合(默认情况下)。如果至少有一个失败,SwiftCheck将显示具体的值。请注意:我们没有指定任何一个具体的数字!基于属性的测试Swift会自动生成数据。



检查往返转换(roundtrip)



这是最常见的模式。假设我们有一个序列化为JSON的结构体。属性是:“序列化和反序列化后,我们得到相同的对

博客

书籍推荐