我有一个单元测试,它调用CNContactStore()
上的方法,例如CNContactStore().execute(saveRequest)
。因此,会弹出联系人的权限对话框,例如推送通知警报,但联系人权限对话框不会自动被解除。我知道如何在使用addUIInterruptionMonitor()
的UI测试中执行此操作,但不知道如何在单元测试中执行此操作。
我认为你将单元测试与UI测试混淆了。在单元测试中,你只想测试你的代码(例如函数和属性),然后你很可能需要“模拟”。
例如,您希望在验证输入字段后测试具有网络调用的登录按钮选择器。
以下应该是步骤:
现在,回到您的问题,您不需要处理系统生成的无法控制和“不可忽略”的警报控制器。相反,你想做的是通过系统触发该访问 - 联系人警报的委托功能来“模拟”(不再是)该弹出事件,“模拟”响应即“不允许”和“好”。当用户点击第一个按钮时,您期望发生什么?第二个按钮?设定期望/断言。
而已。点击您需要点击的所有功能,以增加代码的覆盖范围。如果这有帮助,请告诉我。
我会在CNContactStore
周围创建一个包装器,然后在测试时使用mock。
您对测试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
并使用不同的框架。
希望能帮助到你。