Android中的Monkey測試極大的幫助Android開發(fā)者保證了開發(fā)質(zhì)量抗果,iOS自身是沒有Monkey測試的,最開始有基于UIAutomation 的 monkey 測試[https://github.com/jonathanpenn/ui-auto-monkey]. xCode7之后麸锉,UIAutomation被棄用道宅,對應(yīng)Monkey也隨之淡化.當(dāng)大家習(xí)慣Monkey測試扫倡,突然消失之后就會懷念豹缀,正所謂有需求就會有市場,老外用Swift基于XCUITesting框架開發(fā)新的Monkey工具SwiftMonkey.
Swift Monkey測試
SwiftMonkey基于Swift語言編寫鼠次,按照SwiftMonkey提供的Demo更哄,運行之后看到效果如下圖所示:
SwiftMonkey實現(xiàn)測試需要SwiftMonkey和SwiftMonkeyPaws兩個框架芋齿,如果我們的項目開始就是Swift語言編寫的,那么使用起來就非常簡單,主要過程如下:
①將Demo中SwiftMonkey和SwiftMonkeyPaws兩個項目拖入自身的Swift項目中.
②SwiftMonkey作為FrameWork加入UITest對應(yīng)的Target文件中:
③SwiftMonkeyPaws作為FrameWork加入App項目對應(yīng)的Target中;
④AppDelegate中加入Paws:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var paws: MonkeyPaws?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
paws = MonkeyPaws(view: window!)
return true
}
⑤UITest中加入Monkey測試代碼:
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
XCUIApplication().launch()
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
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
// Initialise the monkey tester with the current device
// frame. Giving an explicit seed will make it generate
// the same sequence of events on each run, and leaving it
// out will generate a new sequence on each run.
//let monkey = Monkey(frame: application.frame)
let monkey = Monkey(seed: 123, frame: application.frame)
// Add actions for the monkey to perform. We just use a
// default set of actions for this, which is usually enough.
// Use either one of these but maybe not both.
// XCTest private actions seem to work better at the moment.
// UIAutomation actions seem to work only on the simulator.
monkey.addDefaultXCTestPrivateActions()
//monkey.addDefaultUIAutomationActions()
// Occasionally, use the regular XCTest functionality
// to check if an alert is shown, and click a random
// button on it.
monkey.addXCTestTapAlertAction(interval: 100, application: application)
// Run the monkey test indefinitely.
monkey.monkeyAround()
}
這段代碼是SwiftMonkey的默認(rèn)代碼成翩,addDefaultXCTestPrivateActions是調(diào)用Apple私有手勢方法觅捆,addDefaultUIAutomationActions只在模擬器中有效,內(nèi)部實現(xiàn)如下:
public func addDefaultXCTestPrivateActions() {
addXCTestTapAction(weight: 25)
addXCTestLongPressAction(weight: 1)
addXCTestDragAction(weight: 1)
addXCTestPinchCloseAction(weight: 1)
addXCTestPinchOpenAction(weight: 1)
addXCTestRotateAction(weight: 1)
//addXCTestOrientationAction(weight: 1) // TODO: Investigate why this does not work.
}
默認(rèn)執(zhí)行點擊麻敌,長按栅炒,拖拽,捏合术羔,旋轉(zhuǎn)赢赊,橫豎屏切換操作,Weight代表的是時間間隔聂示,如果覺得系統(tǒng)默認(rèn)的操作過多,可以自行刪減.
monkeyAround代表次數(shù)簇秒,默認(rèn)如果不設(shè)置次數(shù)鱼喉,會一直執(zhí)行下去.
public func monkeyAround() {
while true {
actRandomly()
actRegularly()
}
}
OC Monkey 測試
如果你的項目一開始就是Swift編寫,或者已經(jīng)全面遷移到Swift語言趋观,恭喜你下面這段介紹可以忽略了.鑒于目前大部分App都是OC為主扛禽,如果直接按照Swift的套路去使用SwiftMonkey會遇到一些問題,有興趣可以自行實踐皱坛,以下是本人實戰(zhàn)過程.
① 將Demo中SwiftMonkey和SwiftMonkeyPaws兩個項目拖入自身的Swift項目中.
② 將Always Embed Swift Standard Libraries設(shè)置為YES.
③ 正常的套路直接調(diào)用Moneky,MonkeyPaws類编曼,但是事實上無法調(diào)用,折騰了很久剩辟,中間各種報錯.
④ 簡單粗暴的方式是將SwiftMonkey兩個項目中的Swift拷貝到OC項目中:
⑤ AppDelegate中代碼實現(xiàn):
@interface AppDelegate ()
@property (strong, nonatomic) MonkeyPaws *paws;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.paws = [[MonkeyPaws alloc] initWithView:self.window tapUIApplication:true];
return YES;
}
⑤ UITest測試代碼:
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
[[[XCUIApplication alloc] init] launch];
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// Use recording to get started writing UI tests.
[XCUIDevice sharedDevice].orientation = UIDeviceOrientationPortrait;
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testMonkey {
XCUIApplication *application = [XCUIApplication new];
CGRect frame = [[application descendantsMatchingType:XCUIElementTypeAny] elementBoundByIndex:0].frame;
Monkey *monkey = [[Monkey alloc] initWithSeed:123 frame:application.frame];
[monkey addDefaultXCTestPrivateActions];
[monkey addXCTestTapAlertActionWithInterval:100 application:application];
[monkey monkeyAround];
}
如果項目中之前沒有進行過Monkey測試掐场,SwiftMonkey會幫我們測出一些以前開發(fā)中沒有注意的問題.SwiftMonkey涉及調(diào)用XCTesting的私有API,不建議包含SwiftMonkey直接上傳到AppStore.