Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/114.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用协议扩展的模拟依赖项不会调用模拟方法_Ios_Xcode_Swift_Unit Testing_Swift2 - Fatal编程技术网

Ios 使用协议扩展的模拟依赖项不会调用模拟方法

Ios 使用协议扩展的模拟依赖项不会调用模拟方法,ios,xcode,swift,unit-testing,swift2,Ios,Xcode,Swift,Unit Testing,Swift2,我有一个问题,我试图测试一个有两个依赖项的类。依赖项实现一个协议,我将两个同样实现协议的“mock”对象传递给我的测试对象。我在下面的一个小测试应用程序中重现了这个问题 import UIKit // first dependency of `Data` (below) protocol Local {} extension Local { // the default method that I want my app to use when running a // `no

我有一个问题,我试图测试一个有两个依赖项的类。依赖项实现一个协议,我将两个同样实现协议的“mock”对象传递给我的测试对象。我在下面的一个小测试应用程序中重现了这个问题

import UIKit

// first dependency of `Data` (below)
protocol Local {}
extension Local {
    // the default method that I want my app to use when running a
    // `normal` execution mode, i.e. not a test
    func isCached (url : NSURL) -> Bool {
        return true
    }
}

// the actual class definition that the app normally runs
class LocalImpl : Local {}

// much the same as `Local` above
protocol Server {}
extension Server {
    func getURL (url : NSURL) -> NSData? {
        // todo
        return nil
    }
}
class ServerImpl : Server {}

// The object that I want to test.
protocol Data {
    var local : Local { get set }
    var server : Server { get set }
}
extension Data {

    func getData (url : NSURL) -> NSData? {
        if local.isCached(url) {
            return nil
        } else {
            return server.getURL(url)
        }
    }
}
class DataImpl : Data {
    var local : Local
    var server : Server

    init () {
        local = LocalImpl()
        server = ServerImpl()
    }

    init (server : Server, local : Local) {
        self.server = server
        self.local = local
    }
}


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let data : Data = DataImpl()
        data.getData(NSURL(string: "http://google.com")!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
然后,在我的测试中

@testable import TestingTests

class Test: XCTestCase {

    // the mock server instance I want to use in my test
    class MockServer : Server {
        static var wasCalled = false
        func getURL(url: NSURL) -> NSData? {
            MockServer.wasCalled = true
            return nil
        }
    }

    // the local instance I want to use in my test (with overridden protocol function)
    class MockLocal : Local {
        func isCached (url : NSURL) -> Bool {
            return false
        }
    }

    func testExample() {
        let data = DataImpl(server: MockServer(), local: MockLocal())
        data.getData(NSURL(string: "http://hi.com")!)
        XCTAssert(MockServer.wasCalled == true)
    }
}
上述测试将失败。使用调试器单步执行测试时,将在本地对象上调用
isCached
的协议定义。换句话说,“默认”实现运行,而不是我在测试中定义的实现

如果我在测试文件中设置了断点,则
数据
对象设置正确,并设置了模拟。但是,一旦我进入
getData
函数,尝试从LLDB打印data.local或data.server将产生错误的访问错误(应用程序实际上不会崩溃,但调试器无法打印值)

我是不是遗漏了什么,或者有人能解释一下为什么你不能这么做吗


使用Swift 2运行Xcode 7.3.1时,您需要在协议中声明函数,而不仅仅是在扩展中声明函数

如果变量的类型为协议类型(此处为),且函数未在协议中定义,则它将仅执行协议扩展中定义的函数,而不会像示例中那样在类中执行

如果您还在协议中声明函数,它将首先查看类中是否有实现,并且仅当类中没有实现时才执行协议扩展版本。 这是服务器协议的正确版本

protocol Server {
    func getURL (url : NSURL) -> NSData?
}
extension Server {
    func getURL (url : NSURL) -> NSData? {
        // todo
        return nil
    }
}

我在上检查了这一点,可以帮助您了解发生了什么

您需要在协议中声明函数,而不仅仅是在扩展中声明函数

如果变量的类型为协议类型(此处为),且函数未在协议中定义,则它将仅执行协议扩展中定义的函数,而不会像示例中那样在类中执行

如果您还在协议中声明函数,它将首先查看类中是否有实现,并且仅当类中没有实现时才执行协议扩展版本。 这是服务器协议的正确版本

protocol Server {
    func getURL (url : NSURL) -> NSData?
}
extension Server {
    func getURL (url : NSURL) -> NSData? {
        // todo
        return nil
    }
}

我在上查看了这篇文章,可以帮助您了解正在发生的事情

查看这篇文章。这可能是你的问题。也许吧,尽管我不想像链接文章中的人那样使用多态性。我没有使用任何子类,只是尝试使用实现相同协议的不同类。这可能是你的问题。也许吧,尽管我不想像链接文章中的人那样使用多态性。我没有使用任何子类,只是尝试使用实现相同协议的不同类。谢谢,这修复了它。有点令人失望,我希望不必多次申报。谢谢,这解决了它。有点令人失望,我希望不必多次申报。