unit testing - Swift Mocking Class -
as far know there no possible solution mocking , stubbing methods in swift used in objc ocmock, mockito, etc.
i'm aware of technique described here. quite useful in cases, had deadlock :)
i had service layer had contracts(calling method params return object callback). one(greatly simplified) example:
class bar { func todata() -> nsdata { return nsdata() } } class foo { class func fromdata(data: nsdata) -> foo { return foo() } } class servermanager { let sharedinstance = servermanager() class func send(request: nsdata, response: (nsdata)->()) { //some networking code unrelated problem response(nsdata()) } } class mobileservice1 { final class func contract1(request: bar, callback: (foo) -> ()) { servermanager.send(request.todata()) { responsedata in callback(foo.fromdata(responsedata)) } } //contract2(...), contract3(...), etc }
therefore somewhere in code had following scenario:
func somewhereinthecode(somebool: bool, someobject: bar) { if somebool { mobileservice1.contract1(someobject) { resultfoo in //self.foo = resultfoo } } else { //mobileservice1.contract2(...) } }
and question how heck test this? there better(for testing) alternative code structure without touching contracts themselves?
better late never found solution. make dependency injection of mobileservice1
(or better of it's interface) , mock easily:
//declaring interface protocol mobileservicecontracts: class { static func contract1(request: bar, callback: (foo) -> ()) } //make implementation conform interface class mobileservice1 : mobileservicecontracts { final class func contract1(request: bar, callback: (foo) -> ()) { servermanager.send(request.todata()) { responsedata in callback(foo.fromdata(responsedata)) } } //contract2(...), contract3(...), etc } //inject service func somewhereinthecode(somebool: bool, someobject: bar, serviceprovider: mobileservicecontracts.type = mobileservice1.self) { if somebool { serviceprovider.contract1(someobject) { resultfoo in //self.foo = resultfoo } } else { //mobileservice1.contract2(...) } }
now can change service in tests:
class mockedmobileservice1: mobileservicecontracts { static func contract1(request: bar, callback: (foo) -> ()) { //do whatever mock } } somewhereinthecode(false, someobject: bar(), serviceprovider: mockedmobileservice1.self)
and best part default values can still call old way(not braking change):
somewhereinthecode(false, someobject: bar())
Comments
Post a Comment