首页 > 解决方案 > 在单元测试中,如何以编程方式关闭系统权限对话框?

问题描述

我有一个单元测试,它调用CNContactStore()例如上的方法CNContactStore().execute(saveRequest)。因此会弹出联系人的权限对话框,例如推送通知警报,但联系人权限对话框不会自动关闭。我知道如何在 UI 测试中执行此操作,addUIInterruptionMonitor()但不知道如何在单元测试中执行此操作。

联系权限提醒

标签: iosswiftxcodeunit-testingpermissions

解决方案


我会创建一个包装器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并使用不同的框架。

希望能帮助到你。


推荐阅读