通过单元测试iOS覆盖类方法行为

时间:2017-03-15 08:18:12

标签: ios unit-testing

我的班级ServerHandler有一个班级方法:

+ (void) sendRequestEventToServer:(MyData*) requestDataForCaching                   
                        onSuccess:(void (^)(void))successBlock;

此方法负责向服务器发送HTTP请求。 我在我的程序中从十几个地方调用这个方法。

我的目标是获取将哪些数据发送到服务器,因此我需要在我重写此方法的地方编写测试,而不是将MyData发送到服务器,我的程序应将其发送到Test类。

我尝试了几种方法,但没有一种方法有效。

@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

现在我运行测试:

@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

当我通过[[MyProgram shared] start];运行程序时,它应该调用mocked [ServerHandler sendRequestEventToServer],但它会调用原始方法

我做错了什么?

我也试过OCMock

1 个答案:

答案 0 :(得分:1)

请遵循以下代码,正确执行您的方法。

+ (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);
        }
    });
}

来源 - Method Swizzling

更新 - 使用 jrswizzle 我解决了

在同一个类中添加新方法,即ServerHandler不在类别中,只需调用以下方法

[ServerHandler jr_swizzleClassMethod:@selector(sendRequestEventToServer) withClassMethod:@selector(mockSendRequestEventToServer) error:nil];

然后调用原始方法

[ServerHandler sendRequestEventToServer:nil completion:nil];

以上情况应该可以。

干杯。