iOS開發(fā)自給自足的Mock數(shù)據(jù)

寫這篇的主要原因是開發(fā)中遇到了一些讓人不舒服,也很無(wú)奈的一些事或者流程。

問題是這樣的:

? ? 1.客戶端開發(fā)結(jié)束但接口遲遲不給,工期也快到了,催基本沒什么結(jié)果。

? ? 2.開發(fā)網(wǎng)絡(luò)環(huán)境經(jīng)常性的被鏟除或因?yàn)楹笈_(tái)調(diào)試環(huán)境,一直處于異常。

? ? 3.等等一些其他原因,不說(shuō)了。

如何自給自足完成客戶端開發(fā)流程(而非聯(lián)調(diào))呢,Mock數(shù)據(jù)似乎是最好的方案之一,好吧繼續(xù)看,先做再說(shuō)。

一、整體實(shí)現(xiàn)架構(gòu)

方案1:可以是編寫假接口如下

- (void)queryServerDataWithRequest:(NSURLRequest *)request completion:(void(^)(id data, NSError *error))completion {

? ? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

? ? ? ? NSDictionary *param = @{@"key1":@"value1",@"key2":@"value2",@"key3":@"value3",@"key4":@"value4"};

? ? ? ? if(completion) {

? ? ? ? ? ? completion(param, nil);

? ? ? ? }

? ? });

}

方案2:可以設(shè)架Mock服務(wù)器,請(qǐng)求和正常的請(qǐng)求一樣,重點(diǎn)在Mock服務(wù)器,關(guān)鍵還是對(duì)別人有依賴。

那么客戶端又沒什么更好點(diǎn)的方法,自給自足不寫假接口呢?當(dāng)然有,我真理的方案是用蘋果的黑魔法NSURLProtocol,攔截請(qǐng)求并接管,將事先準(zhǔn)備好的請(qǐng)求數(shù)據(jù)下發(fā)給接口。

Mack框架

先看圖,接口發(fā)出請(qǐng)求被NSURLProtocol攔截,此時(shí)此刻請(qǐng)求的控制權(quán)就到你手上了:

1.可以繼續(xù)發(fā)起請(qǐng)求把請(qǐng)求的數(shù)據(jù)轉(zhuǎn)接給接口,監(jiān)控了數(shù)據(jù)。

2.從本地讀取已經(jīng)準(zhǔn)備好的數(shù)據(jù),根據(jù)請(qǐng)求過來(lái)的參數(shù)選擇不同的數(shù)據(jù)給請(qǐng)求接口(就算沒網(wǎng)絡(luò)也可以讓接口正常返回?cái)?shù)據(jù))。

二、具體實(shí)現(xiàn)Mock代碼

首先需要注冊(cè)NSURLProtocol子類作為監(jiān)聽接口:

static NSString* const URLProtocolHandledKey = @"URLProtocolHandledKey";

static IMP g_implementationFunc = NULL;

@implementation DPRequestMonitor

static NSArray *ProtocolClasses(id self, SEL _cmd) {

? ? return @[[DPRequestMonitor class]];

}

+ (void)load {

? ? [NSURLProtocol registerClass:self];

? ? Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");

? ? Method method = class_getInstanceMethod(cls, @selector(protocolClasses));

? ? method_setImplementation(method, (IMP)ProtocolClasses);

}

//更多函數(shù)實(shí)現(xiàn)省略。。。

@end

實(shí)現(xiàn)部分還有其他配合如下:

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;

- (void)startLoading;

- (void)stopLoading;

在startLoading中實(shí)現(xiàn)如下:

- (void)startLoading {

? ? [NSURLProtocol setProperty:@(YES) forKey:URLProtocolHandledKey inRequest:(NSMutableURLRequest *)self.request];

? ? [DPResponseManager queryDataWithKey:self.request completion:^(NSData *data, NSError *error) {

? ? ? ? if(!error) {

? ? ? ? ? ? //[self.client URLProtocol:self didReceiveResponse:nil cacheStoragePolicy:NSURLCacheStorageNotAllowed];

? ? ? ? ? ? [self.client URLProtocol:self didLoadData:data];

? ? ? ? ? ? [self.client URLProtocolDidFinishLoading:self];

? ? ? ? }

? ? ? ? else {

? ? ? ? ? ? [self.client URLProtocol:self didFailWithError:error];

? ? ? ? }

? ? }];

}

下面說(shuō)明下接口返回的數(shù)據(jù):

[DPResponseManager queryDataWithKey]

首先返回是一個(gè)json格式數(shù)據(jù),這種數(shù)據(jù)來(lái)源于plist(方便編輯)。

本地?cái)?shù)據(jù)目錄
plist文件內(nèi)容結(jié)構(gòu)

IgnoreRequestParam:目的在于忽略Mock請(qǐng)求是否關(guān)心上行參數(shù),不管心的情況下默認(rèn)讀取并返回response1

RequestParam:請(qǐng)求上行參數(shù),當(dāng)IgnoreRequestParam等于NO時(shí)用此參數(shù)配對(duì)ResponseData,如request1 <-> response1

ResponseData:用來(lái)配置接口返回?cái)?shù)據(jù)。

至此,不要?jiǎng)庸こ檀a的情況下,你可以封裝程framework,在提交測(cè)試前記得移除,怕出錯(cuò)可以做成工程可配置話。簡(jiǎn)單的mock基本實(shí)現(xiàn),開發(fā)不再依賴后臺(tái)接口,而且返回的數(shù)據(jù)想怎么修改怎么修改,不再看臉色吃飯了。順利開發(fā)完成就等聯(lián)調(diào)進(jìn)測(cè)試。

三、好用的Mock工具會(huì)更友好

自此自給自足的Mock可以算是結(jié)束了,但是如何再次基礎(chǔ)上做的更好呢??

比如關(guān)注開發(fā)A接口,但是希望用戶可以登陸狀態(tài)獲取用戶信息參數(shù),因此你需要這么做:

代碼寫死跳過登陸,直接寫死用戶信息參數(shù),直接調(diào)起A接口對(duì)應(yīng)的模塊,編寫Mock數(shù)據(jù)。當(dāng)然也有其他方法可以解決這樣的問題。

但是我這邊打算介紹的是如何簡(jiǎn)單而不改寫過多的代碼實(shí)現(xiàn)一套完整的Mock系統(tǒng)(不過這里不會(huì)過于復(fù)雜描述,更多細(xì)節(jié)后續(xù)有時(shí)間再補(bǔ)充)。

改進(jìn)框架

在開發(fā)App前鏈接到生產(chǎn)環(huán)境,獲取接口控制權(quán),此刻發(fā)起網(wǎng)絡(luò)請(qǐng)求并獲取到線上的正常交互數(shù)據(jù)并保存到本地,可按照請(qǐng)求接口連接的path來(lái)布置獲取的數(shù)據(jù)保存文件,文件格式建議使用plist。也就是上面做開發(fā)用的Mock數(shù)據(jù)。

多點(diǎn)擊幾個(gè)頁(yè)面,尤其是自己關(guān)心的頁(yè)面,以及將要開發(fā)的頁(yè)面必進(jìn)過的頁(yè)面。登陸流程等等。這一步其實(shí)是采集數(shù)據(jù)。

總結(jié):至此請(qǐng)求Mock的系統(tǒng)可以完成數(shù)據(jù)采集、手動(dòng)修改、手動(dòng)添加接口、使用Mock數(shù)據(jù)等工作。

除此之外可以有更多想法,比如采集這一塊保留,但是做Mock的這一部分移植到自建服務(wù)器,數(shù)據(jù)來(lái)自于客戶端收集。這樣一來(lái)多平臺(tái)可以開發(fā)使用。

實(shí)現(xiàn)過程基本結(jié)束,有興趣更多細(xì)節(jié)可以留言,有不妥的地方歡迎拍磚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容