在上線以後發生了幾回崩潰閃退, 須要緊急修復的狀況以後, 我決定我要動手了...javascript
分析了這幾回狀況以後, 發現其實大的邏輯都沒有錯, 可是細的東西特別容易出簍子, 例如說布爾條件寫反了, 某個 @IBOutlet
的控件更名了, 刪掉了, 忘了去 storyboard 裏處理掉它, 就會發生 setValue: forUndefinedKey:
的錯誤, 原本我是想直接 swizzle 掉這個方法, 不讓它拋出錯誤, 可是想一想又以爲不值得. 難道終於要開始學一下怎麼寫測試了嗎?java
而後忽然想起了以前好像看到過一個 UI 測試的框架, 能夠自動幫忙測試 UI, 找到以後就開始用, 而後一發不可收拾.git
倉庫的位置在這裏 GitHub - zalando/SwiftMonkey: A framework for doing randomised UI testing of iOS appsgithub
這個庫讓我想起了無限猴子理論, 其實也相似, 就是產生間隔一段事件就產生一個隨機操做事件, 例如點擊拖拽, 閃退的話是最容易發現的, 或者是你看到一些錯誤的數據和 UI 呈現.(效果圖是張 gif, 手機端加載可能會比較慢)swift
這個庫分紅兩部分:網絡
官方文檔目前還不是很詳細, 我花了一點時間才把這個庫給搞明白, 因此大概介紹一下接入流程.app
包管理, 很簡單嘛, 支持 Carthage 和 Cocoapods 兩種方式, 想用哪一個用哪一個.框架
但使用 Cocoapods 的同窗有一點事情要注意, 做者忘了 push podspec 到主倉庫了, 因此咱們 pod 裏搜索和安裝的都是 1.0.0 版本, 最低支持 iOS 9.0, 而最新的 1.0.1 版本最低支持 8.0.dom
解決方法也很簡單, pod 的時候指定倉庫就好了, 就像這樣:ide
pod 'SwiftMonkey', :git => 'https://github.com/zalando/SwiftMonkey.git'複製代碼
安裝完以後, 在 AppDelegate 裏面咱們須要初始化一下 SwiftMonkeyPaws, 有視覺效果畢竟會更好一點
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 裏聲明一個 paws 去維持引用計數, 而後 MonkeyPaws 就會 swizzle 掉 UITouch 的方法, 讓每次點擊, 拖拽都會有相應的視覺效果.
這裏咱們看到一個 CommandLine.argments.contains(「—MonkeyPaws」)
可能會比較奇怪, 這段代碼是爲了區分開 app 是否跑在測試模式下的, 而後爲了避免在正式版里加入這段代碼, 咱們還加上了 compile flag 去判斷是否編譯這段代碼. 直接加一個 ConfiguationSet 也行, 但不優雅, 也不必...
接下里咱們就去處理 UI 測試的代碼:
import SwiftMonkey
class UITest: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
let app = XCUIApplication()
app.launchArguments.append("--MonkeyPaws")
app.launch()
}
}複製代碼
在 setup 方法裏, 須要注意的就是最好把 continueAfterFailure
設爲 false, 讓代碼出錯時可以停留在出錯的位置那裏, 方便咱們 DEBUG, 畢竟咱們使用的不是常規的測試方法, 測試用例跟代碼之間沒有一一對應的關係.
還有一個就是加上參數 —-MonkeyPaws
去區分運行和測試狀態, 不加的話 paws 就不會運行了.
那麼久該開始寫用例了, 我用的方式比較粗暴.
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)
}複製代碼
前面的代碼是我照抄官方給的例子的, 不加的話會有 bug.
接着咱們初始化一隻 Monkey, 而後給它添加一些動做, 其實還有什麼各類 pinch, peek, pop 之類的, 但個人項目比較簡單, 因此我就只加了點擊和拖拽動做, weight 是間隔. monkeyAround
就是開始隨機操做, iteration 是操做的次數, 操做滿 360000 次就會中止.
這基本上就是個人用法, 裏面還有一些挺有趣的東西, 以後有空的話我還會再探索一下, 例如添加多幾個用例, 而後先跳轉到新寫的 ViewController 那裏, 讓這隻猴子把裏面的東西全都搞亂, 看看有啥 bug.
到目前位置我用了這個庫兩三天, 天天中午去吃飯都會跑一下, 發現了幾個 bug, 三個是低級錯誤, 兩個比較隱晦, 主要是關於屢次點擊重複觸發關鍵事件, 例如說一秒內連續點了七八次提交訂單, 致使發出去七八個請求, 實際在網絡狀況很差的時候, 用戶也有可能心急屢次點擊, 因此挺好的, 幫我提早預防了一些問題.
其實以爲不管是哪一種狀況, 都挺適合用一下這個庫去找到一些低級的明顯的 bug, 強烈推薦你們用一下.
以爲我寫的還不錯的話能夠關注一下個人博客