Ios 使用协议扩展的模拟依赖项不会调用模拟方法
我有一个问题,我试图测试一个有两个依赖项的类。依赖项实现一个协议,我将两个同样实现协议的“mock”对象传递给我的测试对象。我在下面的一个小测试应用程序中重现了这个问题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
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
}
}
我在上查看了这篇文章,可以帮助您了解正在发生的事情查看这篇文章。这可能是你的问题。也许吧,尽管我不想像链接文章中的人那样使用多态性。我没有使用任何子类,只是尝试使用实现相同协议的不同类。这可能是你的问题。也许吧,尽管我不想像链接文章中的人那样使用多态性。我没有使用任何子类,只是尝试使用实现相同协议的不同类。谢谢,这修复了它。有点令人失望,我希望不必多次申报。谢谢,这解决了它。有点令人失望,我希望不必多次申报。