iOS 單元測(cè)試異步 Api, MVP + Kiwi + Mock

摘要

現(xiàn)在大部分的iOS應(yīng)用都是先從網(wǎng)絡(luò)獲取數(shù)據(jù)揍愁,在做相應(yīng)的處理蝴悉,數(shù)據(jù)的獲取一般是在異步線程里做,所以做單元測(cè)試比較麻煩。這里主要介紹Kiwi 的用法偷崩,Kiwi 是 unit test 框架,已經(jīng)封裝好了很多XTest 的Api ,使用起來非常方便撞羽。項(xiàng)目結(jié)構(gòu)是用MVP 架構(gòu)的阐斜,因?yàn)檫@種架構(gòu)比較容易進(jìn)行測(cè)試。項(xiàng)目的測(cè)試Demo 已發(fā)到Github诀紊,https://github.com/Alimjan2009/AAMVPUnitTest

1. 準(zhǔn)備好項(xiàng)目

測(cè)試demo

我的測(cè)試demo 功能很簡(jiǎn)單谒出,點(diǎn)擊獲取信息按鈕以后,發(fā)送http 請(qǐng)求獲取數(shù)據(jù)邻奠,再展示到label 里邊
相應(yīng)的代碼如下:

  • PlaceInfoViewController.m
//
//  PlaceInfoViewController.m
//  AAMVPUnitTest
//
#import "PlaceInfoViewController.h"
#import "PlaceInfoPresenter.h"
@interface PlaceInfoViewController ()<PlaceInfoViewImpl>
@property (weak, nonatomic) IBOutlet UITextField *place;
@property (weak, nonatomic) IBOutlet UILabel *result;
@end
@implementation PlaceInfoViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _presenter = [[PlaceInfoPresenter alloc]initWithView:self];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (IBAction)onGetPlaceInfoPressed:(id)sender {
    [_presenter loadDate:_place.text];
}
-(void)showResult:(NSString*)res{
    _result.text = res;
}
@end
  • PlaceInfoViewController.h
#import <UIKit/UIKit.h>
#import "PlaceInfoPresenter.h"
@interface PlaceInfoViewController : UIViewController
@property (nonatomic, strong) PlaceInfoPresenter *presenter;
@end
  • PlaceInfoPresenter.m
//
//  PlaceInfoPresenter.m
//  AAMVPUnitTest
//

#import "PlaceInfoPresenter.h"
#import "AFNetworking.h"
@implementation PlaceInfoPresenter
- (instancetype)initWithView:(id<PlaceInfoViewImpl>) view
{
    self = [super init];
    if (self) {
        self.view = view;
    }
    return self;
}
-(void)loadDate:(NSString*)placeName{
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    
    manager.responseSerializer =[AFJSONResponseSerializer serializer];
    
    manager.responseSerializer.acceptableContentTypes =  [NSSet setWithObjects:@"application/json",@"text/plain", @"text/html",@"text/json",@"text/javascript", nil];
    //2.設(shè)置登錄參數(shù)
    NSDictionary *dict = @{ @"a":placeName};
    
    //3.請(qǐng)求
    [manager GET:@"http://gc.ditu.aliyun.com/geocoding" parameters:dict success: ^(AFHTTPRequestOperation *operation, id responseObject) {
        NSError *parseError = nil;
        
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:&parseError];
        
        if(_view!=nil)
            [_view showResult:[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]];
    } failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
        
    }];
}
@end

  • PlaceInfoPresenter.h
//
//  PlaceInfoPresenter.h
//  AAMVPUnitTest
//
//  Created by Alimjan on 16/5/4.
//  Copyright ? 2016年 Alimjan. All rights reserved.
//

#import <Foundation/Foundation.h>

@protocol PlaceInfoViewImpl
-(void)showResult:(NSString*)res;
@end

@protocol PlaceInfoPresenterImpl
-(void)loadDate:(NSString*)placeName;
@end

@interface PlaceInfoPresenter : NSObject<PlaceInfoPresenterImpl>
@property (nonatomic, strong) id<PlaceInfoViewImpl> view;

- (instancetype)initWithView:(id<PlaceInfoViewImpl>) view;
@end

2. 集成kiwi

Kiwi 用cocopods 安裝非常方便笤喳。以下是我的Podfile

target 'AAMVPUnitTestTests' , :exclusive => true do
  pod 'Kiwi'
end

3. 寫測(cè)試模塊

創(chuàng)建一個(gè)m 文件,并按照kiwi 格式寫測(cè)試模塊碌宴。我們的presenter 獲取數(shù)據(jù)成功后杀狡,會(huì)調(diào)用showresult ,所以我們只要判斷showresult 是否有被調(diào)用,就能判斷接口是否成功
要是不知道m(xù)ock 是什么贰镣,可以查看Kiwi 的手冊(cè)呜象。

  • PlaceInfoTestSpec.m
//
//  PlaceInfoTestSpec.m
//  AAMVPUnitTest
//
//  Created by Alimjan on 16/5/4.
//  Copyright 2016年 Alimjan. All rights reserved.
//

#import <Kiwi/Kiwi.h>
#import "PlaceInfoViewController.h"
#import "PlaceInfoPresenter.h"
SPEC_BEGIN(PlaceInfoTestSpec)

describe(@"PlaceInfoTest", ^{
    it(@"place info presenter test", ^{
        //
        // mock the view and stub the showResult method
       // 我們要測(cè)試api, 不關(guān)心view膳凝, 所以我們可以mock view
        id viewMock = [KWMock mockForProtocol:@protocol(PlaceInfoViewImpl)];
        [ [viewMock should] conformToProtocol:@protocol(PlaceInfoViewImpl)];
        
        [viewMock stub:@selector(showResult:) ];
        
        // init presenter
        // 初始化我們的presenter
        PlaceInfoPresenter *presenter = [[PlaceInfoPresenter alloc]initWithView:viewMock];
        
        // send asnc request
        // 測(cè)試我們的 業(yè)務(wù)
        [presenter loadDate:@"北京"];
        
        //wait until the show result called
      // 等待3秒,知道show result 方法被調(diào)用恭陡。我們的presenter 獲取數(shù)據(jù)成功后蹬音,會(huì)調(diào)用showresult ,所以我們只要判斷showresult 是否有被調(diào)用,就能判斷接口是否成功
        [[viewMock shouldEventuallyBeforeTimingOutAfter(3.0)]receive:@selector(showResult:) withCount:1];
      });
  });
SPEC_END
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末休玩,一起剝皮案震驚了整個(gè)濱河市著淆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拴疤,老刑警劉巖牧抽,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異遥赚,居然都是意外死亡扬舒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門凫佛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讲坎,“玉大人,你說我怎么就攤上這事愧薛〕靠唬” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵毫炉,是天一觀的道長(zhǎng)瓮栗。 經(jīng)常有香客問我,道長(zhǎng)瞄勾,這世上最難降的妖魔是什么费奸? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮进陡,結(jié)果婚禮上愿阐,老公的妹妹穿的比我還像新娘。我一直安慰自己趾疚,他們只是感情好缨历,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著糙麦,像睡著了一般辛孵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赡磅,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天魄缚,我揣著相機(jī)與錄音,去河邊找鬼仆邓。 笑死鲜滩,一個(gè)胖子當(dāng)著我的面吹牛伴鳖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播徙硅,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼榜聂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了嗓蘑?” 一聲冷哼從身側(cè)響起须肆,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桩皿,沒想到半個(gè)月后豌汇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泄隔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拒贱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佛嬉。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逻澳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暖呕,到底是詐尸還是另有隱情斜做,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布湾揽,位于F島的核電站瓤逼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏库物。R本人自食惡果不足惜霸旗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望艳狐。 院中可真熱鬧定硝,春花似錦、人聲如沸毫目。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镀虐。三九已至,卻和暖如春沟绪,著一層夾襖步出監(jiān)牢的瞬間刮便,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工绽慈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恨旱,地道東北人辈毯。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像搜贤,于是被迫代替她去往敵國(guó)和親谆沃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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