iOS開(kāi)發(fā) | 如何為網(wǎng)絡(luò)接口編寫(xiě)單元測(cè)試

純工具類APP已經(jīng)淪為炮灰,移動(dòng)APP幾乎都是基于網(wǎng)絡(luò)的慨代,因此寫(xiě)單元測(cè)試更哄,網(wǎng)絡(luò)是一個(gè)繞不開(kāi)的話題芋齿。實(shí)際iOS開(kāi)發(fā)中腥寇,凡是基于http的網(wǎng)絡(luò)連接, AFNetworking 幾乎已成為一個(gè)標(biāo)準(zhǔn)庫(kù)觅捆,比如發(fā)起一個(gè)post請(qǐng)求赦役,會(huì)創(chuàng)建AFHTTPSessionManager 對(duì)象:

 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"text/html",nil];

并調(diào)用以下方法:

- (NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
                      progress:(void (^)(NSProgress * _Nonnull))uploadProgress
                       success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                       failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure

網(wǎng)絡(luò)接口為什么難測(cè)?

還記得《沒(méi)有單元測(cè)試栅炒,何談重構(gòu)》 中的測(cè)試循環(huán)嗎掂摔?讓我們?cè)賮?lái)復(fù)習(xí)一下:

測(cè)試循環(huán)

當(dāng)我們?yōu)锳FHTTPSessionManager編寫(xiě)單元測(cè)試時(shí),會(huì)遇到以下問(wèn)題:

1. 返回結(jié)果不可控

雖然我們可以準(zhǔn)備我們想要的目標(biāo)URLString赢赊、parameters等參數(shù)乙漓,但在實(shí)際網(wǎng)絡(luò)中,progress释移、success叭披、failure等block回調(diào)——也就是測(cè)試循環(huán)的“驗(yàn)證結(jié)果”部分——是不確定的。
即使能勉強(qiáng)控制測(cè)試的網(wǎng)絡(luò)環(huán)境玩讳,保證服務(wù)器一定返回success涩蜘,定制返回?cái)?shù)據(jù)也困難重重:準(zhǔn)備把目標(biāo)返回?cái)?shù)據(jù)都寫(xiě)在服務(wù)端?基于真實(shí)的網(wǎng)絡(luò)熏纯,很難獲得理想的數(shù)據(jù)同诫。

鬼知道服務(wù)器會(huì)返回給你什么!
——某開(kāi)發(fā)者云

2. 可能還有經(jīng)濟(jì)上的問(wèn)題

假設(shè)要開(kāi)發(fā)的是對(duì)接獲取驗(yàn)證碼接口的方法樟澜,難道運(yùn)行一次就真的請(qǐng)求一個(gè)短信驗(yàn)證碼剩辟?短信下發(fā)平臺(tái)可是會(huì)¥扣錢¥的。更何況往扔,萬(wàn)一第三方平臺(tái)沒(méi)有響應(yīng)或超時(shí)贩猎,我們的測(cè)試就失敗了,這種異步的萍膛、不確定的測(cè)試吭服,無(wú)論從金錢還是時(shí)間上衡量,都不夠經(jīng)濟(jì)蝗罗,因此很難實(shí)現(xiàn)艇棕。

因此,我們需要有方法指定返回?cái)?shù)據(jù)串塑,并且不需要 實(shí)際訪問(wèn)網(wǎng)絡(luò)沼琉,我們這里選擇使用OCMock。

使用OCMock

OCMock是一個(gè)用于建立仿造對(duì)象的框架桩匪,它使用OC的運(yùn)行時(shí)機(jī)制打瘪,可以自動(dòng)的創(chuàng)建任何OC對(duì)象實(shí)例, 比如可以這樣來(lái)仿制 AFHTTPSessionManager 對(duì)象:

id mockManager = [OCMockObject mockForClass:[AFHTTPSessionManager class]];

準(zhǔn)備數(shù)據(jù)

接著我們就可以使用mockManager提供的 andDo 方法,“偽造”出一個(gè)success調(diào)用:

[[[mockManager expect] andDo:^(NSInvocation *invocation) {
        void (^successBlock)(NSURLSessionDataTask *task, id responseObject) = nil;
        [invocation getArgument:&successBlock atIndex:5];
        successBlock([[NSURLSessionDataTask alloc] init],
                     @{@"keyTest":@"valueTest"}
                     );
    }] POST:[OCMArg any]
     parameters:nil
     progress:[OCMArg any]
     success:[OCMArg any]
     failure:[OCMArg any]];

調(diào)用expect 方法用來(lái)告訴OCMock “接管” POST方法,附加的 andDo block方法中闺骚,提供了 NSInvocation 對(duì)象彩扔,這使得我們有機(jī)會(huì)指定調(diào)用的block和返回值:

  1. 先聲明 successBlock ,注意僻爽,格式要與調(diào)用的block聲明一致虫碉;
  2. 通過(guò) getArgument 指定調(diào)用success方法,atIndex用于指明希望調(diào)用參數(shù)的位置胸梆,這里要從2開(kāi)始敦捧,前兩位分別是self(target),selector(_cmd));
  3. 調(diào)用successBlock碰镜,傳入希望返回的數(shù)據(jù)绞惦。

注意:[OCMArg any] 用于告訴OCMock,可以接受任何參數(shù)洋措,反之,如果expert時(shí)杰刽,POST參數(shù)傳@"aTestPath"菠发,調(diào)用時(shí)任何非@"aTestPath"的POST調(diào)用將被忽略。

調(diào)用接口

[mockManager POST:@"any path"
            parameters:nil
              progress:nil
               success:^(NSURLSessionDataTask *task, id responseObject) {
                   XCTAssertEqual(@"valueTest", responseObject[@"keyTest"]);
               } failure:^(NSURLSessionDataTask * _Nullable task,
                           NSError * _Nonnull error) {
               }];

這時(shí)贺嫂,success block將會(huì)回調(diào)滓鸠,并傳回我們?cè)?code>andDo中指明的字典數(shù)據(jù)@{@"keyTest":@"valueTest"}

到此,我們已經(jīng)有了一個(gè)測(cè)試網(wǎng)絡(luò)應(yīng)用的良好開(kāi)端第喳,基于這里介紹的技術(shù)糜俗,我們可以改造iOS開(kāi)發(fā)中的網(wǎng)絡(luò)接口,使之能更方便編寫(xiě)單元測(cè)試曲饱,歡迎關(guān)注溪石iOS悠抹,留言、私信分享你的感想和經(jīng)驗(yàn)扩淀,共同探討iOS單元測(cè)試中的奇技淫巧楔敌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市驻谆,隨后出現(xiàn)的幾起案子卵凑,更是在濱河造成了極大的恐慌,老刑警劉巖胜臊,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺卢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡象对,警方通過(guò)查閱死者的電腦和手機(jī)黑忱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杨何,你說(shuō)我怎么就攤上這事酱塔。” “怎么了危虱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵羊娃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我埃跷,道長(zhǎng)蕊玷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任弥雹,我火速辦了婚禮垃帅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剪勿。我一直安慰自己贸诚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布厕吉。 她就那樣靜靜地躺著酱固,像睡著了一般。 火紅的嫁衣襯著肌膚如雪头朱。 梳的紋絲不亂的頭發(fā)上运悲,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音项钮,去河邊找鬼班眯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烁巫,可吹牛的內(nèi)容都是我干的署隘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼亚隙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼定踱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起恃鞋,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤崖媚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后恤浪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體畅哑,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年水由,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荠呐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泥张,靈堂內(nèi)的尸體忽然破棺而出呵恢,到底是詐尸還是另有隱情,我是刑警寧澤媚创,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布渗钉,位于F島的核電站,受9級(jí)特大地震影響钞钙,放射性物質(zhì)發(fā)生泄漏鳄橘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一芒炼、第九天 我趴在偏房一處隱蔽的房頂上張望瘫怜。 院中可真熱鬧,春花似錦本刽、人聲如沸鲸湃。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暗挑。三九已至,卻和暖如春别瞭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背株憾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工蝙寨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嗤瞎。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓墙歪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贝奇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子虹菲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 上篇《iOS開(kāi)發(fā) | 如何為網(wǎng)絡(luò)接口編寫(xiě)單元測(cè)試》發(fā)表后,收到不少小伙伴的簡(jiǎn)信掉瞳,提出了不少問(wèn)題毕源,其中一個(gè)典型問(wèn)題是...
    溪石iOS閱讀 2,138評(píng)論 5 10
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)陕习,斷路器霎褐,智...
    卡卡羅2017閱讀 134,665評(píng)論 18 139
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。该镣。冻璃。 其實(shí)如果沒(méi)有APIManager這一層是沒(méi)法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,193評(píng)論 1 23
  • 1、登錄(文本輸入省艳、按鈕交互娘纷、基于網(wǎng)絡(luò)的交互) 2、刷新界面:(表視圖) 1>小部分應(yīng)用程序數(shù)據(jù)來(lái)源于本地 2>更...
    炙冰閱讀 774評(píng)論 0 1
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666閱讀 1,387評(píng)論 0 6