參考源文章
https://github.com/zalando/SwiftMonkey
https://kemchenj.github.io/2017/03/16/2017-03-16/
簡介
這個庫讓我想起了無限猴子理論, 其實也類似, 就是產生間隔一段事件就產生一個隨機操作事件, 例如點擊拖拽, 閃退的話是最容易發現的, 或者是你看到一些錯誤的數據和 UI 呈現.
- 這個庫分成兩部分:
主體是 SwiftMonkey, 依賴於 XCUITest, 調用了一些私有方法去發起操作事件
SwiftMonkeyPaws, 負責呈現操作事件的視覺效果, 上面的動圖里, 那些小手掌就是 SwiftMonkeyPaws 制造出來的, 需要直接接入到 app 里面
安裝步驟
但使用 Cocoapods 的同學有一點事情要注意, 作者忘了 push podspec 到主倉庫了, 所以我們 pod 里搜索和安裝的都是 1.0.0 版本, 最低支持 iOS 9.0, 而最新的 1.0.1 版本最低支持 8.0.
解決方法也很簡單, pod 的時候指定倉庫就行了, 就像這樣:
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 產生.
其實覺得無論是哪種情況, 都挺適合用一下這個庫去找到一些低級的明顯的 bug, 強烈推薦大家用一下.