我有一个单元测试,该单元调用CNContactStore()
上的方法,例如CNContactStore().execute(saveRequest)
。因此,会弹出联系人权限对话框,如“推送通知”警报,但不会自动取消联系人权限对话框。我知道如何在addUIInterruptionMonitor()
的UI测试中执行此操作,但不知道如何在单元测试中执行此操作。
答案 0 :(得分:1)
我认为您将单元测试与 UI测试混淆了。在单元测试中,您只想测试代码(例如,函数和属性),并因此可能需要“模拟”。
例如,您要在验证输入字段后测试具有网络调用的登录按钮选择器。
以下应为步骤:
现在,回到您的问题,您无需处理系统生成的不可控制且“不可禁用”的警报控制器。相反,您要执行的操作是通过点击系统的该访问联系人警报的委托功能来“模拟”(不是再次)该弹出事件,“模拟”响应即“不允许” “ 和“确定” 。当用户点击第一个按钮时,您期望发生什么?第二个按钮?设定期望/主张。
就是这样。点击您需要点击的每个功能以增加代码的覆盖范围。让我知道是否有帮助。
答案 1 :(得分:1)
我会在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
}
或者您可以将其声明为var
,然后为其提供默认值
所以代替:
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
并使用其他框架,就可以这样做。
希望有帮助。