我有一个问题,我试图测试一个有两个依赖项的类。依赖项实现了一个协议,我传递了两个“模拟”对象,这些对象也实现了我的测试对象的协议。我在下面的一个小测试应用程序中重现了这个问题。
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)
}
}
上述测试将失败。使用调试器逐步执行测试时,将在Local对象上调用isCached
的协议定义。换句话说,“默认”实现运行而不是我在测试中定义的实现。
如果我在测试文件中设置了断点,则Data
对象设置正确并设置了我的模拟。但是,一旦我进入getData
函数,尝试从LLDB打印出data.local或data.server会产生错误的访问错误(应用程序实际上不会崩溃,但调试器无法打印该值)
我在这里遗漏了什么,或者有人可以向我解释为什么你不能这样做?
使用Swift 2运行Xcode 7.3.1
答案 0 :(得分:0)
您需要在协议中声明该功能,而不仅仅是在扩展名中。
如果变量的类型属于协议(此处为),并且函数未在协议中定义,则它将仅执行协议扩展中定义的函数,而不执行示例中的类。
如果您还在协议中声明了该函数,它将首先查看该类中是否存在实现,并且仅当该类中没有实现时才执行协议扩展版本。 以下是服务器协议的更正版本。
protocol Server {
func getURL (url : NSURL) -> NSData?
}
extension Server {
func getURL (url : NSURL) -> NSData? {
// todo
return nil
}
}
我在IBM Swift Sandbox上查看了此内容,this post可以帮助您了解正在发生的事情