Reputation: 5713
I have class ServerHandler
with one class method:
+ (void) sendRequestEventToServer:(MyData*) requestDataForCaching
onSuccess:(void (^)(void))successBlock;
This method is responsible to send HTTP request to Server. I call this method from dozen places in my program.
My goal is to get what data is sent to server therefore I need to write test where I override this method and instead to send MyData
to server my program should send it to Test class.
I tried several approaches but none of them works.
@interface ServerHandler (TestSupport)
+ (void) mockSendRequestEventToServer:(MyData*) requestDataForCaching onSuccess:(void (^)(void))successBlock;
@end
@implementation ServerHandler (TestSupport)
+ (void) mockSendRequestEventToServer:(MyData*) requestDataForCaching onSuccess:(void (^)(void))successBlock
{
NSLog(@"mockSendRequestEventToServer");
}
+ (void)load {
Method original = class_getClassMethod([ServerHandler class], @selector(sendRequestEventToServer));
Method mocked = class_getClassMethod([ServerHandler class], @selector(mockSendRequestEventToServer));
method_exchangeImplementations(original, mocked);
}
@end
Now I run the test:
@implementation ServerTalkerTests
- (void)setUp {
[super setUp];
[ServerHandler load];
}
- (void) test_serverTalker {
__block BOOL isRunning = YES;
[[MyProgram shared] start];
// ...
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:10];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:timeout];
} while (isRunning);
}
@end
When I run the program through [[MyProgram shared] start];
It should call mocked [ServerHandler sendRequestEventToServer]
but it calls original method
What Im doing wrong?
I also tried with OCMock
Upvotes: 1
Views: 294
Reputation: 12717
Follow the code below, should execute your methods properly.
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(sendRequestEventToServer);
SEL mockedSelector = @selector(mockSendRequestEventToServer);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method mockedMethod = class_getInstanceMethod(class, mockedSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(mockedMethod),
method_getTypeEncoding(mockedMethod));
if (didAddMethod) {
class_replaceMethod(class,
mockedSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, mockedMethod);
}
});
}
Source - Method Swizzling
Update - Using jrswizzle I solved it
Add your new method in the same class ie ServerHandler
not in a category, and just call the following method
[ServerHandler jr_swizzleClassMethod:@selector(sendRequestEventToServer) withClassMethod:@selector(mockSendRequestEventToServer) error:nil];
Then call the original method
[ServerHandler sendRequestEventToServer:nil completion:nil];
The above should work fine.
Cheers.
Upvotes: 1