iOS开发mock接口数据(二)之网络请求匹配

   接上篇我对团队中进行接口数据mock要实现的目标进行了梳理,这一篇我主要给大家说一下具体的实践。
   在网上搜了一下还是有很多这里我就不一一的列举出来了,我这里主要结合GYHttpMock 来进行上层的封装与处理来实现目标的。GYHttpMock使用教程地址
由于GYHttpMock支持正则匹配 HTTP Request,但是这还不够,我们还必须能够根据Head,body,URL,params,网络请求方法GET/POST等参数来匹配到每一个具体的接口。 我这边建了一个GYHttpMock 的category,对- (BOOL)matchesRequest:(id)request 方法进行了重载。具体实现如下:

- (BOOL)matchesRequest:(id)request {
    if ([self matchesMethod:request]
        && [self matchesURL:request]
        && [self matchesParams:request]
        && [self matchesBody:request]
        ) {
        return YES;
    }

    return NO;
}

判断网络请求方法是否相同的方法matchesMethod 实现如下:

/**
 判断方法是否相同
 */
- (BOOL)matchesMethod:(id)request {
    if (!self.method || [self.method caseInsensitiveCompare:request.method] == NSOrderedSame) {
        return YES;
    }
    return NO;
}

判断网络请求的URL是否相同,具体实现如下:

/**
 判断url是否相同,如果get则判断不包含参数的判断 如果post则直接判断
 如果是get在urlMatcher中会带入参数所以在比较时需要去除
 */
- (BOOL)matchesURL:(id)request {
    NSString *url = [self urlWithDeleteParams:request.url.absoluteString];

    //记录传入的url
    NSString *noParamsURL = [[self urlWithDeleteParams:self.urlMatcher.string] copy];
    NSDictionary *params = [self paramsWithURL:self.urlMatcher.string];
    objc_setAssociatedObject(self, paramsKey, params, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    return [url hasSuffix:noParamsURL];
}

/**
 去除url中的参数
 */
- (NSString *)urlWithDeleteParams:(NSString *)url {
    NSArray *temp = [url componentsSeparatedByString:@"?"];
    return temp.count == 2 ? temp[0] : url;
}

/**
 url的参数 返回key:value
 */
- (NSDictionary *)paramsWithURL:(NSString *)url {
    if (![url isKindOfClass:[NSString class]] || url.length == 0) {
        return nil;
    }

    NSArray *urls = [url componentsSeparatedByString:@"?"];
    NSString *paramsURL = nil;
    if (urls.count == 2) {
        paramsURL = urls[1];
    }

    return [self convertDictionaryWithURLParams:paramsURL];
}

匹配发送请求的参数:

/**
 匹配参数:只匹配参数名不匹配参数值
 */
- (BOOL)matchesParams:(id)request {
    NSDictionary *params = [self paramsWithURL:request.url.absoluteString];
    NSDictionary *oldParams = objc_getAssociatedObject(self, paramsKey);
    return [self dictionary:params isEqualDictionary:oldParams];
}

/**
 判断两个字典是否相同 只判断key
 */
- (BOOL)dictionary:(NSDictionary *)a isEqualDictionary:(NSDictionary *)b {
    if (![a isKindOfClass:[NSDictionary class]] || ![b isKindOfClass:[NSDictionary class]] || a.count != b.count) {
        return NO;
    }

    NSMutableArray *aKeys = [a.allKeys mutableCopy];
    NSArray *bKeys = [b.allKeys copy];

    [aKeys removeObjectsInArray:bKeys];
    return aKeys.count == 0;
}

判断请求头是否为空

/**
 判断头是否相同
 */
- (BOOL)matchesHeaders:(id)request {
    for (NSString *header in self.headers) {
        if (![[request.headers objectForKey:header] isEqualToString:[self.headers objectForKey:header]]) {
            return NO;
        }
    }

    return YES;
}

判断请求体body是否相同:

/**
 判断body 只有在post的情况下才有效
 */
- (BOOL)matchesBody:(id)request {
    NSData *reqBody = request.body;
    if (!reqBody) {
        return YES;
    }

    NSString *reqBodyString = [[NSString alloc] initWithData:reqBody encoding:NSUTF8StringEncoding];
    NSAssert(reqBodyString, @"request body is nil");

    NSDictionary *params = [self convertDictionaryWithURLParams:reqBodyString];
    NSDictionary *mockParams = [self convertDictionaryWithURLParams:self.body.string];
    return [self dictionary:params isEqualDictionary:mockParams];
}


/**
 判断两个字典是否相同 只判断key
 */
- (BOOL)dictionary:(NSDictionary *)dic1 isEqualDictionary:(NSDictionary *)dic2 {

    NSSet *setA = [NSSet setWithArray:[dic1 allKeys]];
    NSSet *setB = [NSSet setWithArray:[dic2 allKeys]];
    return [setA isEqualToSet:setB];
}

通过以上这些方法我们就能够匹配到具体的网络请求了,在下面一篇文章里我将为大家分享如何根据匹配到的数据配置mock数据。

你可能感兴趣的:(IOS)