I've got a Swift class that I'm unit testing. The main purpose of the class is to make HTTP calls. I just finished mocking all networking requests using Mockingjay, but I want to make sure that going forward I don't forget to mock future requests. While I was doing the initial mocking I replaced the base URL I'm using with one that doesn't work, but I'd like to keep that in place only for my tests. The class under test looks like this:
public class MyWebServiceWrapper {
...
public class var baseURL: String {
return "https://api.thesite.com"
}
...
}
I've tried to use OCMock from an Objective-C class to replace baseURL
's implementation, and I've tried using method swizzling as described on NSHipster as well (I made the class derive from NSObject
and replaced baseURL
with a method instead of the property shown above - I'd rather not swizzle, especially since I otherwise don't need the class to be an NSObject
subclass).
This is the code I used to perform the attempted swizzle, which had no effect. For both the attempted solutions below, I rewrote my class under test like so (since it looked like neither approach would work well with Swift properties or pure Swift classes):
@objc public class MyWebServiceWrapper: NSObject {
...
public class var baseURL: String {
return baseURLValue()
}
public class func baseURLValue() -> String {
return "https://api.thesite.com"
}
...
}
This was my swizzling attempt (in Swift). Based on the log, I hit the else
statement every time, in case it helps figure out what's going on.
extension MyWebServiceWrapper {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
if self !== MyWebServiceWrapper.self {
return
}
dispatch_once(&Static.token) {
NSLog("Replacing MyWebServiceWrapper base URL...")
let originalSelector = #selector(baseURLValue)
let swizzledSelector = #selector(networkFreeBaseURL)
guard let klass = object_getClass(self) else {
return
}
let originalMethod = class_getClassMethod(klass, originalSelector)
let swizzledMethod = class_getClassMethod(klass, swizzledSelector)
let didAddMethod = class_addMethod(klass, originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod))
if didAddMethod {
NSLog("MyWebServiceWrapper method added")
class_replaceMethod(klass, swizzledSelector, method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
NSLog("MyWebServiceWrapper implementation replaced")
}
}
}
class func networkFreeBaseURL() -> String {
return "https://tests-shouldnt-hit-the-network.com"
}
}
This is how I tried to replace the method using OCMock (in Objective-C). The code is called during the configuration of my unit tests.
id wrapperMock = OCMClassMock([MyWebServiceWrapper class]);
OCMStub(ClassMethod([wrapperMock baseURLValue])).andReturn(@"https://tests-shouldnt-hit-the-network.com");
What's the correct way to achieve my goal of returning an invalid value from baseURL
?