使用延迟和拒绝进行验证需要花费大量时间来运行测试



我的项目使用OCMock、OHHTTPStubs和XCTest。我尝试测试SDK(由我实现的SDK),所以我截取Http响应/请求,并添加一些对回调方法的期望。每个单元测试都有一些期望,即委托方法将被正确调用,在设置了所有期望之后,我对每个委托方法都包含了拒绝,以确保只调用指定的方法,而不调用其他方法。

我的单元测试示例:

// stub http
... here are some http stubs...
// expect 
[[self.mockDelegate expect] didSomethigHappend:[OCMArg checkWithBlock:^BOOL(id obj) {
    BOOL result = NO;
    // testing parameter object
    if(result) {
        // call next method on SDK
        [self.objectToTest nextMethod];
    }
    return result;
}] withError:[OCMArg isNil]];
// reject any other call:
[[self.mockDelegate reject] didSomethigHappend:[OCMArg any] withError:[OCMArg any]];
[[self.mockDelegate reject] dodSomethig2:[OCMArg any] withError:[OCMArg any]];
[[self.mockDelegate reject] dodSomethig3:[OCMArg any] withError:[OCMArg any]];
[super.objectToTest doSomethigWithDelegate:super.mockDelegate]; // run
[super.mockDelegate verifyWithDelay:3];  // verify

所有测试都成功通过,但运行所有测试都需要花费大量时间。但我看到的是,当我删除这些拒绝时,所有测试的运行速度都快了3倍。经过一些调试后,我检查了OCMock库方法的实现:

- (void)verifyWithDelay:(NSTimeInterval)delay atLocation:(OCMLocation *)location
{
    NSTimeInterval step = 0.01;
    while(delay > 0)
    {
        if([expectations count] == 0)
            break;
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:step]];
        delay -= step;
        step *= 2;
    }
    [self verifyAtLocation:location];
}

在注册拒绝的地方,"期望值"变量总是包含这些拒绝,因此它会等待所有延迟时间。

有人有同样的问题吗?也许我做错了什么,这是正确的行为?

OCMock有一个bug。

这里有一个方法swizzling的变通方法:

// stubbing verify with delay from ocmock framework
// because ocmock if has any registered rejects
// waits whole specified time, so we need to change this flow
// so it will wait for all expectation has occure and after that wait some steps to make sure that any reject has not invoked
static dispatch_once_t swizzle_token;
dispatch_once(&swizzle_token, ^{
    SEL originalSelector = @selector(verifyWithDelay:);
    SEL swizzledSelector = @selector(fake_verifyWithDelay:);
    Method originalMethod = class_getInstanceMethod([OCMockObject class], originalSelector);
    Method swizzledMethod = class_getInstanceMethod([VDFUsersServiceBaseTestCase class], swizzledSelector);
    BOOL didAddMethod =
    class_addMethod([OCMockObject class],
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod([OCMockObject class],
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
});

这里是fake_verify方法:

- (void)fake_verifyWithDelay:(NSTimeInterval)delay {
NSTimeInterval step = 0.1;
while (delay > 0) {
    @try {
        [self verify];
        break;
    }
    @catch (NSException *e) {}
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:step]];
    delay -= step;
    step += 0.1;
}
[self verify];

}

最新更新