I am trying to test a piece of code where I check to see if an account has already created a secret key and stored it in the keychain. If not it calls a method that starts the oauth process.
My first thought was override the method which I would like to call if the user hasn't got a secret key. However I am using a struct and thus can't inherit and override the method.
If I was using a class I would so something like:
func testInitiateOauthCalledIfSecretKeyNotFound() {
class MockKeychainAccess: KeychainAccess {
var initiateAuthorizationWasCalled: Bool = false
override initiateAuthorization() {
initiateAuthorizationWasCalled = true
}
let keychainAccess = MockKeychainAccess()
keychainAccess.authorizeWithGoogle()
XCTAssertTrue(initiateAuthorizationWasCalled)
}
I haven't tested this code so not sure if it compiles. However logically it seems it would handle the case I am after. If within the authorizeWithGoogle
method we call initiateAuthorization()
then I would know that that has occurred. However one can not do this when they are using a struct as we can't inherit from a struct.
Please note: I am new to TDD so maybe I am thinking about this the wrong way. Other suggestions are welcome. However I do not want to convert from a struct to a class just to write a test. I am using structs as I am trying to be more swift like.
Does anyone know a way I could test whether a function is called within a struct?
==========
Edit:
In response to dasdom answer I am adding an example of the general approach I am trying to achieve:
override func viewDidLoad() {
setupView()
let api = DataApi()
getData(api)
}
func setupView() {
tableView.dataSource = tableViewDataSource
}
func getData(api: DataApi) {
api.getApplicationData( { (objects) in
if let applications = objects as? [Application] {
self.tableViewDataSource.setApplicationItems(applications)
self.tableView.reloadData()
}
else {
// Display error
}
})
}
So I would like to inject the MockDataApi so that it can return what I want as the method takes in a type of DataApi. However I am not sure how I should create this MockDataApi struct and pass it into this method.
Could someone help in regards to how to build this mock object for this purpose and use it? I realise it's with protocols but struggling to piece it together.
Use a protocol. Make your class/struct and your test mock conform to the protocol. Inject the dependency and assert that the expected method gets called in your mock.
protocol DataApiProtocol {
func getApplicationData(block: [AnyObject] -> Void)
}
// Production code
struct DataApi: DataApiProtocol {
func getApplicationData(block: [AnyObject] -> Void) {
// do stuff
}
// more properties and methods
}
// Mock code
struct MockDataApi: DataApiProtocol {
var getApplicationDataGotCalled = false
func getApplicationData(block: [AnyObject] -> Void) {
getApplicationDataGotCalled = true
}
}
// Test code
func testGetData_CallsGetApplicationData() {
let sut = MyAwesomeClass()
let mockDataApi = MockDataApi()
sut.getData(mockDataApi)
XCTAssertTrue(mockDataApi.getApplicationDataGotCalled)
}
I hope this helps.