ios - 在单元测试中,如何以编程方式关闭系统权限对话框?
问题描述
我有一个单元测试,它调用CNContactStore()
例如上的方法CNContactStore().execute(saveRequest)
。因此会弹出联系人的权限对话框,例如推送通知警报,但联系人权限对话框不会自动关闭。我知道如何在 UI 测试中执行此操作,addUIInterruptionMonitor()
但不知道如何在单元测试中执行此操作。
解决方案
我会创建一个包装器CNContactStore
,然后在测试时使用模拟。
您对测试并不真正感兴趣CNContactStore
,您对测试代码CNContactStore
是否正确交互感兴趣?
设置
我将开始创建协议和类以从您的“正常”代码库中提取联系人内容。
首先是一个Contact
结构,用于保存稍后创建实际所需的属性CNContact
struct Contact {
//holds whichever properties you need to create a CNContact
}
然后是一个保存您想要执行的方法的协议。这可以通过具有很多类似方法的协议来完成
protocol ContactsHolder {
func save(contact: Contact)
func add(contact: Contact)
func delete(contact: Contact)
func update(contact: Contact)
//Maybe more methods, the important thing is that you abstract yourself away from CNContactStore and other Contact kit classes
}
或者你可以像这样创建一个enum
持有可能的选项
enum ContactsUpdateMethod {
case save(Contact)
case add(Contact)
case delete(Contact)
case update(Contact)
}
protocol ContactsHolder {
func execute(_ method: ContactsUpdateMethod)
}
在你的“真实”代码中
有了这些,您就可以创建实际的 ContactsHolder,然后在内部使用它CNContactStore
以及与该框架相关的所有内容。
例如(如果您选择具有“纯”save
功能的版本)
class CNContactsHolder: ContactsHolder {
func save(contact: Contact) {
//1. create a `CNContact` from your `Contact`
//2. create a saveRequest
//3. execute: CNContactStore().execute(saveRequest)
}
....
}
然后你给需要工作的班级CNContactStore
参考你的新ContactsHolder
协议
所以在你的课上你有
let contactsHolder: ContactsHolder
然后你可以在你的init
方法中传递它
init(contactsHolder: ContactsHolder = CNContactsHolder()) {
self.contactsHolder = contactsHolder
}
或者你可以将它声明为 avar
然后给它一个默认值
所以而不是:
let contactsHolder: ContactsHolder
你说:
var contactsHolder: ContactsHolder = CNContactsHolder()
重要的是,当您需要测试时,您可以将ContactsHolder
“真实”更改为模拟CNContactsHolder
在您的测试代码中
为了测试这一点,您创建了一个模拟:
struct MockContactsHolder: ContactsHolder {
var saveWasCalled = false
func save(contact: Contact) {
saveWasCalled = true
}
}
然后你在你的课堂上使用它而不是CNContactsHolder
现在您应该能够测试自己的代码,而不会被与您的代码无关的权限和内容打断,但是使用CNContactStore
.
免责声明:)
我没有通过编译器运行上述内容,因此可能存在拼写错误。
此外,可能会丢失一些零碎的东西以使其适合CNContact
(回调等),但我希望您了解如何将事物分开。
最后......这似乎需要做很多工作,但我认为将“特定于框架”的代码放到一个单独的帮助类中,隐藏在协议后面是有意义的,这样您就可以在需要时将其换掉例如进行测试,或者......如果您决定稍后摆脱CNContact
并使用不同的框架。
希望能帮助到你。
推荐阅读
- r - 使用另一个多边形裁剪/剪辑复杂 SpatialPolygonsDataFrame 的最快方法
- mysql - 如何在准备好的语句中跳过变量单引号的形成?
- dotnetrdf - 如何使用 dotNetRDF 调用带有不记名令牌的 RDF 数据源?
- twitter-bootstrap - 如何在 nuxt.js 中使用 uiv 模块
- arrays - 字符串的构造
- ssl - Gitlab Enterprise 和 Atlassian Jira 集成 - SSL 证书验证错误
- python - 如何找到我的 xlsx 表中存在的带有熊猫的缺失列?
- javascript - WebComponents 向侧边栏添加元素
- asp.net - 使用 Azure AD JWT (id_token) 登录我的 API
- javascript - 从 URL 参数(作为字节)到 JSON 字符串