養(yǎng)一只”無限猴子”幫你測試

在上線之后發(fā)生了幾次崩潰閃退, 需要緊急修復(fù)的情況之后, 我決定我要?jiǎng)邮至?..

分析了這幾次情況之后, 發(fā)現(xiàn)其實(shí)大的邏輯都沒有錯(cuò), 但是細(xì)的東西特別容易出簍子, 例如說布爾條件寫反了, 某個(gè) @IBOutlet 的控件改名了, 刪掉了, 忘了去 storyboard 里處理掉它, 就會(huì)發(fā)生 setValue: forUndefinedKey: 的錯(cuò)誤, 本來我是想直接 swizzle 掉這個(gè)方法, 不讓它拋出錯(cuò)誤, 但是想想又覺得不值得. 難道終于要開始學(xué)一下怎么寫測試了嗎?

然后突然想起了之前好像看到過一個(gè) UI 測試的框架, 可以自動(dòng)幫忙測試 UI, 找到之后就開始用, 然后一發(fā)不可收拾.

倉庫的位置在這里 GitHub - zalando/SwiftMonkey: A framework for doing randomised UI testing of iOS apps

簡介

這個(gè)庫讓我想起了無限猴子理論, 其實(shí)也類似, 就是產(chǎn)生間隔一段事件就產(chǎn)生一個(gè)隨機(jī)操作事件, 例如點(diǎn)擊拖拽, 閃退的話是最容易發(fā)現(xiàn)的, 或者是你看到一些錯(cuò)誤的數(shù)據(jù)和 UI 呈現(xiàn).(效果圖是張 gif, 手機(jī)端加載可能會(huì)比較慢)

68747470733a2f2f7468756d62732e6766796361742e636f6d2f496e646f6c656e7454616c6c466f78746572726965722d73697a655f726573747269637465642e676966.gif

這個(gè)庫分成兩部分:

  1. 主體是 SwiftMonkey, 依賴于 XCUITest, 調(diào)用了一些私有方法去發(fā)起操作事件
  2. SwiftMonkeyPaws, 負(fù)責(zé)呈現(xiàn)操作事件的視覺效果, 上面的動(dòng)圖里, 那些小手掌就是 SwiftMonkeyPaws 制造出來的, 需要直接接入到 app 里面

接入流程

官方文檔目前還不是很詳細(xì), 我花了一點(diǎn)時(shí)間才把這個(gè)庫給搞明白, 所以大概介紹一下接入流程.

包管理, 很簡單嘛, 支持 Carthage 和 Cocoapods 兩種方式, 想用哪個(gè)用哪個(gè).

但使用 Cocoapods 的同學(xué)有一點(diǎn)事情要注意, 作者忘了 push podspec 到主倉庫了, 所以我們 pod 里搜索和安裝的都是 1.0.0 版本, 最低支持 iOS 9.0, 而最新的 1.0.1 版本最低支持 8.0.

Screen Shot 2017-03-16 at 8.34.06 PM.png

解決方法也很簡單, pod 的時(shí)候指定倉庫就行了, 就像這樣:

pod 'SwiftMonkey', :git => 'https://github.com/zalando/SwiftMonkey.git'

安裝完之后, 在 AppDelegate 里面我們需要初始化一下 SwiftMonkeyPaws, 有視覺效果畢竟會(huì)更好一點(diǎn)

import SwiftMonkeyPaws

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var paws: MonkeyPaws?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        #if DEBUG
            if CommandLine.arguments.contains("--MonkeyPaws") {
                paws = MonkeyPaws(view: window!)
            }
        #endif
        
        return true
    }
}

記得要在 AppDelegate 里聲明一個(gè) paws 去維持引用計(jì)數(shù), 然后 MonkeyPaws 就會(huì) swizzle 掉 UITouch 的方法, 讓每次點(diǎn)擊, 拖拽都會(huì)有相應(yīng)的視覺效果.

這里我們看到一個(gè) CommandLine.argments.contains(“—MonkeyPaws”) 可能會(huì)比較奇怪, 這段代碼是為了區(qū)分開 app 是否跑在測試模式下的, 然后為了不在正式版里加入這段代碼, 我們還加上了 compile flag 去判斷是否編譯這段代碼. 直接加一個(gè) ConfiguationSet 也行, 但不優(yōu)雅, 也沒必要...

接下里我們就去處理 UI 測試的代碼:

import SwiftMonkey

class UITest: XCTestCase {
        
    override func setUp() {
        super.setUp()
        
        continueAfterFailure = false

        let app = XCUIApplication()
        app.launchArguments.append("--MonkeyPaws")
        app.launch()
    }
}

在 setup 方法里, 需要注意的就是最好把 continueAfterFailure 設(shè)為 false, 讓代碼出錯(cuò)時(shí)能夠停留在出錯(cuò)的位置那里, 方便我們 DEBUG, 畢竟我們使用的不是常規(guī)的測試方法, 測試用例跟代碼之間沒有一一對(duì)應(yīng)的關(guān)系.

還有一個(gè)就是加上參數(shù) —-MonkeyPaws 去區(qū)分運(yùn)行和測試狀態(tài), 不加的話 paws 就不會(huì)運(yùn)行了.

那么久該開始寫用例了, 我用的方式比較粗暴.

func testMonkey() {
    let application = XCUIApplication()

    // Workaround for bug in Xcode 7.3. Snapshots are not properly updated
    // when you initially call app.frame, resulting in a zero-sized rect.
    // Doing a random query seems to update everything properly.
    // TODO: Remove this when the Xcode bug is fixed!
    _ = application.descendants(matching: .any).element(boundBy: 0).frame

    let monkey = Monkey(frame: application.frame)
 
    monkey.addXCTestTapAction(weight: 25)
    monkey.addXCTestDragAction(weight: 200)
    monkey.addXCTestTapAction(weight: 100)
    monkey.addXCTestDragAction(weight: 30)
        
    monkey.monkeyAround(iterations: 360000)
}

前面的代碼是我照抄官方給的例子的, 不加的話會(huì)有 bug.

接著我們初始化一只 Monkey, 然后給它添加一些動(dòng)作, 其實(shí)還有什么各種 pinch, peek, pop 之類的, 但我的項(xiàng)目比較簡單, 所以我就只加了點(diǎn)擊和拖拽動(dòng)作, weight 是間隔. monkeyAround 就是開始隨機(jī)操作, iteration 是操作的次數(shù), 操作滿 360000 次就會(huì)停止.

這基本上就是我的用法, 里面還有一些挺有趣的東西, 之后有空的話我還會(huì)再探索一下, 例如添加多幾個(gè)用例, 然后先跳轉(zhuǎn)到新寫的 ViewController 那里, 讓這只猴子把里面的東西全都搞亂, 看看有啥 bug.

使用體驗(yàn)

到目前位置我用了這個(gè)庫兩三天, 每天中午去吃飯都會(huì)跑一下, 發(fā)現(xiàn)了幾個(gè) bug, 三個(gè)是低級(jí)錯(cuò)誤, 兩個(gè)比較隱晦, 主要是關(guān)于多次點(diǎn)擊重復(fù)觸發(fā)關(guān)鍵事件, 例如說一秒內(nèi)連續(xù)點(diǎn)了七八次提交訂單, 導(dǎo)致發(fā)出去七八個(gè)請(qǐng)求, 實(shí)際在網(wǎng)絡(luò)情況不好的時(shí)候, 用戶也有可能心急多次點(diǎn)擊, 所以挺好的, 幫我提前預(yù)防了一些問題.

其實(shí)覺得無論是哪種情況, 都挺適合用一下這個(gè)庫去找到一些低級(jí)的明顯的 bug, 強(qiáng)烈推薦大家用一下.

覺得我寫的還不錯(cuò)的話可以關(guān)注一下我的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浇辜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陪白,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咱士,死亡現(xiàn)場離奇詭異轧钓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)毕箍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來文捶,“玉大人,你說我怎么就攤上這事粹排。” “怎么了顽耳?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵射富,是天一觀的道長。 經(jīng)常有香客問我胰耗,道長限次,這世上最難降的妖魔是什么宪郊? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任拖陆,我火速辦了婚禮,結(jié)果婚禮上依啰,老公的妹妹穿的比我還像新娘。我一直安慰自己速警,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布长豁。 她就那樣靜靜地躺著忙灼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪该园。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天啃勉,我揣著相機(jī)與錄音双妨,去河邊找鬼叮阅。 笑死枝嘶,一個(gè)胖子當(dāng)著我的面吹牛帘饶,可吹牛的內(nèi)容都是我干的群扶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼缴饭,長吁一口氣:“原來是場噩夢啊……” “哼骆莹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起幕垦,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疚察,沒想到半個(gè)月后仇奶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體貌嫡,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岛抄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年狈茉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氯庆。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖感凤,靈堂內(nèi)的尸體忽然破棺而出粒督,到底是詐尸還是另有隱情陪竿,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布闰挡,位于F島的核電站礁哄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏桐绒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一咧叭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菲茬,春花似錦派撕、人聲如沸婉弹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佩脊。三九已至垫卤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間穴肘,已是汗流浹背舔痕。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伯复,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓侍匙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親想暗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,499評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫杨箭、插件储狭、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,022評(píng)論 4 62
  • 作者設(shè)計(jì)思路 1.YYMemoryCache YYMemoryCache負(fù)責(zé)管理內(nèi)存緩存。這個(gè)類是線程安全的擒悬。 L...
    WeiHing閱讀 645評(píng)論 0 7
  • 設(shè)置快捷啟動(dòng)方式在Ubuntu下稻艰,每次都要找到 pycharm.sh所在的文件夾懂牧,執(zhí)行./pycharm.sh尊勿,非...
    張不二01閱讀 281評(píng)論 0 0
  • 光陰荏苒,轉(zhuǎn)瞬間的流逝躯保!人生一世,值得謹(jǐn)記于心的人與事能有多少途事!很多時(shí)候你會(huì)說:我自私!誰又會(huì)懂得自私的緣由尸变!很多...
    承諾詮釋人生閱讀 257評(píng)論 0 0