gpt4 book ai didi

ios - 模拟使用协议(protocol)扩展的依赖项不会调用模拟方法

转载 作者:行者123 更新时间:2023-11-28 08:36:43 25 4
gpt4 key购买 nike

我在尝试测试具有两个依赖项的类时遇到问题。依赖项实现了一个协议(protocol),我将两个也实现了协议(protocol)的“模拟”对象传递给我的被测对象。我在下面的一个小测试应用程序中重现了这个问题。

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 的协议(protocol)定义将在 Local 对象上调用。换句话说,“默认”实现运行而不是我在测试中定义的实现。

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

我是不是遗漏了什么,或者有人可以向我解释为什么你不能这样做吗?

使用 Swift 2 运行 Xcode 7.3.1

最佳答案

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

如果你的变量类型是协议(protocol)的(这里是),并且函数没有在你的协议(protocol)中定义,它将只执行在协议(protocol)扩展中定义的函数,而不是在你的例子中的类中。

如果你在协议(protocol)中也声明了函数,它会首先查看类中是否有实现,只有在类中没有实现时才执行协议(protocol)扩展版本。这是您的服务器协议(protocol)的更正版本。

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

我在 IBM Swift Sandbox 上检查过这个和 this post可以帮助您了解正在发生的事情

关于ios - 模拟使用协议(protocol)扩展的依赖项不会调用模拟方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37532093/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com