加入我们的 Slack 社区!-> 邀请链接在此
目录
概述
SwiftyMocky 是一个强类型框架,提供类似于 Mockito 的单元测试体验。该库依赖于 Sourcery,它会扫描您的源代码并 为您生成 Mock Swift 代码!
SwiftyMocky 的想法是自动模拟 Swift 协议和协议组合。主要功能包括
- 易于使用的语法,利用自动完成的全部功能,使编写测试更加容易和快速
- 我们支持泛型
- 生成模拟实现
- 指定模拟将返回什么(给定)
- 可以为不同属性指定不同的返回值
- 记录被模拟的返回值序列
- 验证方法是否被模拟调用过
- 根据指定的属性检查方法的调用
- 它与真实设备一起工作
重要!!! 版本 4.1.x
命令行界面(CLI)已经移回到主(此)存储库。此存储库中的CLI将至少支持到版本5.0.0。
版本 4.0.x
当前版本有几个重大变更。它删除了过时的方法(可能破坏性),并废弃了在新的存储库中包含CLI。
SwiftyPrototype也被提取到单独的库中。不再需要编译标志,因此如果您依赖带有-DMockyCustom
的SwiftyMocky
,您将不得不切换到SwiftyPrototype
。
我们认为当前版本是稳定的。我们正在转向使用新的Mockfile,但将仍然支持之前的配置格式。库与Swift 4.1, 4.2, 5.0, 5.1.2和Sourcery 1.0.x兼容。
虽然技术上可以在Linux目标上集成SwiftyMocky,但尚无Mock生成功能。尽管如此,您可以通过SwiftPM使用SwiftyMokcy运行时,只要您对在mac机器上生成mock没有异议。
从3.2.0及以下进行迁移
迁移不是必需的,您可以像以前一样继续使用SwiftyMocky
。在Legacy setup部分描述了Legacy setup
。
尽管如此,我们仍然鼓励您尝试新的CLI
并分享反馈。我们相信它将使使用和设置SwiftyMocky
变得更为容易。如果您有现有的设置,请按照此指南安装CLI并尝试。
> swiftymocky migrate
入门指南
1. Integrate SwiftyMocky
SwiftyMocky可以通过CocoaPods获取。要安装它,只需将以下行添加到您的Podfile中
pod "SwiftyMocky"
使用项目目录下的CLI工具
# To setup initial Mockfile
% ./Pods/SwiftyMocky/bin/swiftymocky init
# To generate mocks
% ./Pods/SwiftyMocky/bin/swiftymocky generate
要安装,请向您的Cartfile添加以下内容
github "MakeAWishFoundation/SwiftyMocky"
然后执行carthage update
对于Carthage,还需要执行额外的几个步骤
您需要安装CLI以生成模拟,请参阅[安装][#installation]
将SwiftyMocky添加到您的Package.swift依赖中
dependencies: [
.package(url: "https://github.com/MakeAWishFoundation/SwiftyMocky", from: "4.1.0-pre"),
]
您需要安装CLI以生成模拟,请参阅[安装][#installation]
注意:有关SwiftyMocky作为单元测试工具或原型框架集成示例,请见此处:https://github.com/MakeAWishFoundation/SM-Integration-Tests
2. 安装SwiftyMocky CLI
> brew install mint
> mint install MakeAWishFoundation/SwiftyMocky-CLI
> marathon install MakeAWishFoundation/SwiftyMocky-CLI
Make:
从https://github.com/MakeAWishFoundation/SwiftyMockyCLI克隆,并在根目录中运行make
3. 生成模拟
标注将要被模拟的协议,使其采用AutoMockable
协议,或者在源代码中定义它们的上方添加注释。
模拟将从您的项目根目录生成,基于Mockfile内的配置。
> path/to/swiftymocky setup # if you don't have a Mockfile yet
> path/to/swiftymocky doctor # validate your setup
> path/to/swiftymocky generate # generate mocks
如果您不想迁移到我们的CLI并希望使用“原始”Sourcery,请参阅文档中的此部分。
用法
1. 伪造成要模拟的标记协议
在项目中某处创建“占位符”协议,例如:protocol AutoMockable { }
将其用于每个实际要模拟的协议。
protocol ToBeMocked: AutoMockable {
// ...
}
或者,使用 Sourcery 注释标记需要模拟的协议,如下所示
//sourcery: AutoMockable
protocol ToBeMocked {
// ...
}
或用于协议组合
typealias ToBeMocked = OneProtocol & TwoProtocols & AutoMockable
源目录中每个具有此注释的协议都将被添加到Mock.generated.swift
2. 模拟伪代码方法返回值 - 给定
所有模拟都有一个名为 given 的方法(可以作为实例方法或全局函数访问),具有易于使用的语法,允许指定给定方法的返回值(基于指定的属性)。
所有协议方法都很好地纳入了 Given,并有匹配的签名。这允许使用自动完成功能(只需键入 .
)来查看所有模拟的协议方法,并为它们指定返回值。
所有方法属性都被封装为 Parameter 枚举,允许在 any
和 value
之间选择,从而为模拟行为提供极大的灵活性。请考虑以下
Given(mock, .surname(for name: .value("Johnny"), willReturn: "Bravo"))
Given(mock, .surname(for name: .any, willReturn: "Kowalsky"))
print(mock.surname(for: "Johny")) // Bravo
print(mock.surname(for: "Mathew")) // Kowalsky
print(mock.surname(for: "Joanna")) // Kowalsky
在3.0版中,我们引入了序列和策略,以更好地控制模拟行为。
Given(mock, .surname(for name: .any, willReturn: "Bravo", "Kowalsky", "Nguyen"))
print(mock.surname(for: "Johny")) // Bravo
print(mock.surname(for: "Johny")) // Kowalsky
print(mock.surname(for: "Johny")) // Nguyen
print(mock.surname(for: "Johny")) // and again Bravo
// ...
有关更多详细信息,请参阅完整的文档。
3. 检查方法、子脚本和属性的调用 - 验证
所有模拟都有一个名为 verify 的方法(可以作为实例方法或全局函数访问),具有易于使用的语法,允许验证是否在模拟上调用了某个方法,以及调用的次数。它还提供了方便的方式来指定方法属性是否重要(以及哪些属性)。
所有协议方法都很好地纳入了 Verify,并有匹配的签名。这允许使用自动完成功能(只需键入 .
)来查看所有模拟的协议方法,并指定要验证哪一个。
所有方法属性都被封装为 Parameter 枚举,允许在 any
、value
和 matching
之间选择,从而为测试提供极大的灵活性。请考虑以下
// inject mock to sut. Every time sut saves user data, it should trigger storage storeUser method
sut.usersStorage = mockStorage
sut.saveUser(name: "Johny", surname: "Bravo")
sut.saveUser(name: "Johny", surname: "Cage")
sut.saveUser(name: "Jon", surname: "Snow")
// check if Jon Snow was stored at least one time
Verify(mockStorage, .storeUser(name: .value("Jon"), surname: .value("Snow")))
// storeUser method should be triggered 3 times in total, regardless of attributes values
Verify(mockStorage, 3, .storeUser(name: .any, surname: .any))
// storeUser method should be triggered 2 times with name Johny
Verify(mockStorage, 2, .storeUser(name: .value("Johny"), surname: .any))
// storeUser method should be triggered at least 2 times with name longer than 3
Verify(mockStorage, .moreOrEqual(to: 2), .storeUser(name: .matching({ $0.count > 3 }), surname: .any))
对于 Verify,您可以使用 Count 来指定预期触发某事的次数。 Count 可以定义为显式值,如 1
、2
,... 或更有描述性和灵活性的方式,如 .never
、more(than: 1)
等。
从SwiftyMocky 3.0版本开始,可以自由地使用Given
和进行Verify
操作,不仅限于是否是读取或设置属性。
mock.name = "Danny"
mock.name = "Joanna"
print(mock.name)
// Verify getter:
Verify(mock, 1, .name)
// Verify setter:
Verify(mock, 2, .name(set: .any))
Verify(mock, 1, .name(set: .value("Danny")))
Verify(mock, .never, .name(set: .value("Bishop")))
4. 当模拟方法被调用时采取行动 - 执行
所有模拟都拥有执行方法(既可以作为实例方法也可以作为全局函数访问),语法简单易用,允许指定闭包,当模拟方法被调用时将执行该闭包。
它使用了与Given相同的参数包装功能,因此可以根据不同的属性设置指定不同的执行情况。
当使用基于完成块的方法时,这非常方便。
示例
// Perform allows to execute given closure, with all the method parameters, as soon as it is being called
Perform(mock, .methodThatTakesCompletionBlock(completion: .any, perform: { completion in
completion(true,nil)
}))
文档
完整的文档可以在此处找到,也可以在docs目录下找到。
指南 - 目录
变更日志可以在此处找到
所有支持的功能
使用示例
要查看更多示例,请查看我们示例项目或指南中的示例部分指南。
要运行示例项目,首先从示例目录中克隆存储库,然后运行pod install
。
要触发模拟生成,从根目录(如果您安装了命令行工具)运行rake mock
或swiftymocky generate
。
路线图
- 以优雅的方式模拟协议
- 生成模拟模板
- 示例项目
- 使用变量模拟协议
- 生成方法签名,避免命名冲突
- 单元测试覆盖框架代码库的95%
- 文档覆盖框架代码库的95%
- 为模板添加单元测试
- 支持tvOS、Linux和MacOS
- Carthage支持
- 支持下标
- 作为序列返回模拟值
- 简化配置过程的简单工具
作者
- Przemysław Wośko, [email protected]
- Andrzej Michnia, [email protected]
许可
SwiftyMocky可以在MIT许可下使用。更多信息请参阅LICENSE文件。