I have an issue where I am trying to test a class that has two dependencies. The dependencies implement a protocol, and I pass two 'mock' objects that also implement the protocol(s) to my object under test. I have reproduced the problem in a small test app below.
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.
}
}
Then, in my test
@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)
}
}
The above test will fail. When stepping through the test with a debugger, the protocol definition of isCached
will be called on the Local object. In other words, the "default" implementation runs instead of the one that I defined in my test.
If I set breakpoints in my test file, the Data
object is set up properly and has my mocks set. However, once I step into the getData
function, trying to print out data.local or data.server from LLDB will produce bad access errors (app doesn't actually crash, but the debugger cannot print the value)
Am I missing something here, or can someone explain to me why you cannot do this?
Running Xcode 7.3.1 with Swift 2
Aucun commentaire:
Enregistrer un commentaire