2016-05-30 27 views
1

我有一個問題,我試圖測試一個有兩個依賴關係的類。依賴關係實現一個協議,並且我將兩個'模擬'對象也傳遞給我的被測對象。我在下面的一個小測試應用程序中轉載了這個問題。使用協議擴展的嘲弄依賴不會調用模擬方法

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將產生錯誤的訪問錯誤(應用程序實際上不會崩潰,但調試器無法打印該值)

是我在這裏丟失一些東西,或者有人可以向我解釋爲什麼你不能這樣做?

與斯威夫特2

+0

看看這個[SO](http://stackoverflow.com/questions/31795158/swift-2-protocol -extension-not-calling-overriden-method-correctly)文章。這可能是你的問題。 –

+0

也許,雖然我沒有試圖在鏈接文章中使用多態。我沒有使用任何子類,只是試圖使用所有實現相同協議的不同類。 – bendecoste

回答

0

運行的Xcode 7.3.1你需要聲明函數的協議,而不是僅在擴展。

如果變量的類型是協議(在這裏),並且該協議中沒有定義該函數,那麼它將只執行在協議擴展中定義的函數,而不是類中的函數。

如果您還在協議中聲明函數,它將首先查看類中是否存在實現,並且只有在類中沒有實現時才執行協議擴展版本。 以下是您的服務器協議的更正版本。

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

我檢查這個對IBM Swift Sandboxthis post可以幫助您瞭解正在發生的事情

+0

謝謝,這固定了它。有點令人失望,我希望不必多次申報。 – bendecoste