我希望通过协议扩展现有的NetworkExtension类,以便对我的代码进行单元测试。
我首先为NEVPNManager创建了协议
protocol NEVPNManagerProtocol {
var connection : ConnectionProtocol { get } // <-- Doesn't work
func loadFromPreferences(completionHandler: @escaping (Error?) -> Swift.Void)
func saveToPreferences(completionHandler: ((Error?) -> Swift.Void)?)
}
extension NEVPNManager: NEVPNManagerProtocol {}然后是connection属性的单独协议,将其存根掉。
protocol ConnectionProtocol {
var status: NEVPNStatus { get }
func stopVPNTunnel()
func startVPNTunnel() throws
}
extension NEVPNConnection : ConnectionProtocol {}在NEVPNManager内部,我可以看到我正在确认属性签名,但是Xcode不相信我,并声称:
类型'NEVPNManager‘不符合协议'NEVPNManagerProtocol’
它试图像这样自动修正它:
extension NEVPNManager: NEVPNManagerProtocol {
var connection: ConnectionProtocol {
<#code#>
}
}但是在NEVPNManager中查看签名,在我看来是正确的:
/*!
* @property connection
* @discussion The NEVPNConnection object used for controlling the VPN tunnel.
*/
@available(iOS 8.0, *)
open var connection: NEVPNConnection { get }有什么建议吗?
发布于 2018-03-21 02:22:56
嘲笑这一点很棘手,因为苹果控制着NEVPNManager及其NEVPNConnection的实例化。
您所看到的错误是因为您试图重新定义connection属性,而您不能这样做。NEVPNManager已经具有类型为NEVPNConnection的connection属性。
我们可以使用第一个协议(修改)和两个模拟类的组合来模拟connection属性。
首先,该协议需要稍加修改:
protocol NEVPNManagerProtocol {
var connection : NEVPNConnection { get } // <-- has to be this type
func loadFromPreferences(completionHandler: @escaping (Error?) -> Swift.Void)
func saveToPreferences(completionHandler: ((Error?) -> Swift.Void)?)
}
extension NEVPNManager: NEVPNManagerProtocol {}接下来,我们需要一个模拟连接类,因为connection属性必须是NEVPNConnection类型的类,或者是从该类型继承的类。在这里引入协议似乎没有多大好处,因为我们试图模拟类的行为,我们可以更直接地使用模拟。
class MockNEVPNConnection: NEVPNConnection {
override var status: NEVPNStatus {
return NEVPNStatus.connected //or whatever
}
override func stopVPNTunnel() {
print("MockNEVPNConnection.stopVPNTunnel")
}
override func startVPNTunnel() throws {
print("MockNEVPNConnection.startVPNTunnel")
}
}最后,我们需要一个返回模拟连接的模拟管理器类。使用模拟管理器是我能够注入模拟连接的唯一方法。
模拟管理器符合NEVPNManagerProtocol并返回模拟连接对象。(注意:当试图直接从NEVPNManager继承时,我的游乐场在实例化模拟时崩溃了。)
class MockNEVPNManager: NEVPNManagerProtocol {
var connection: NEVPNConnection {
return MockNEVPNConnection()
}
func loadFromPreferences(completionHandler: @escaping (Error?) -> Swift.Void) {
print("MockNEVPNManager.loadFromPreferences")
}
func saveToPreferences(completionHandler: ((Error?) -> Swift.Void)?) {
print("MockNEVPNManager.saveToPreferences")
}
}客户端类必须接受一个类型为NEVPNManagerProtocol而不是NEVPNManager的对象,这样我们就可以将模拟传递给它。
class MyClient {
let manager: NEVPNManagerProtocol
init(manager: NEVPNManagerProtocol) {
self.manager = manager
}
}在现实生活中,我们可以把真正的经理传递给我们的客户:
let myClient = MyClient(manager: NEVPNManager.shared())在我们的测试中,我们可以通过模拟:
let myMockedClient = MyClient(manager: MockNEVPNManager())和调用连接上的方法:
try? myMockedClient.manager.connection.startVPNTunnel()
//prints "MockNEVPNConnection.startVPNTunnel"https://stackoverflow.com/questions/49385623
复制相似问题