Bill Dyer Bill Dyer - 6 months ago 31
Swift Question

Mocking a Protocol with a Generic Func

So I have the following Swift protocols...

protocol MyMessage {
func encodeMessage() -> [String:AnyObject]
}

protocol Sender {
func send<T:MyMessage>(id:Int,event:T)
}


And I am using them just fine in some code I wrote. Now I want to write some unit tests and mock the Sender protocol. Basically I want to capture the id and the event so I can check them in a unit test in which I pass a Sender into the class under test. So I started writing the mock and I got this far before I realized it wasn't going to work.

class MockSender<U : MyMessage> : Sender {
var sentEvent : U?
var sentId : Int?

func send<T:U>(id:Int,event:T) {
sendId = id
// save message so I can verify it
sentEvent = event
}
}


The problem is that I can't figure out how to tie the type of U to the type of T. The compiler says U is not a protocol, which makes sense. If I replace U with T in the MockSender signature the sendEvent = event line gets flagged with the error that I can't assign something of type T to something of type _?. From what I know about Swift generics I understand why I am getting these errors. What I would like to know is if there is someway I can do what I am trying to do, basically mock the protocol with the generic function and capture the value so I can verify it.

Answer

You have to match the function's signature when implementing it:

class MockSender<U: MyMessage> : Sender {
    var sentId: Int?
    var sentEvent: U?

    func send<T : MyMessage>(id: Int, event: T) {
        sentId = id
        sentEvent = event as? U
    }
}

Usage:

struct Message: MyMessage {
    func encodeMessage() -> [String : AnyObject] {
        return ["firstName": "John", "lastName": "Smith"]
    }
}

let msg = Message()

let mock = MockSender<Message>()
mock.send(1, event: msg)

print(mock.sentEvent?.encodeMessage()) // Optional(["firstName": John, "lastName": Smith])
Comments