ui automonkey

来源:https://github.com/jonathanpenn/ui-auto-monkey

// Copyright (c) 2013 Jonathan Penn (http://cocoamanifest.net/)

// Permission is hereby granted, free of charge, to any person obtaining a copy

// of this software and associated documentation files (the "Software"), to deal

// in the Software without restriction, including without limitation the rights

// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

// copies of the Software, and to permit persons to whom the Software is

// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in

// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

// THE SOFTWARE.

var target = UIATarget.localTarget();

var app = target.frontMostApp();

var window = app.mainWindow();

target.logElementTree();

"use strict";

var target = UIATarget.localTarget();

function UIAutoMonkey() {

this.config = {

//run either by minutesToRun or numberOfEvents. Only one of these can set. (To use minutes you can use config.numberOfEvents = 0)

//minutesToRun = 60 * 8; //sample to run for 8 hours.

//checkTimeEvery = 60; //how often to check (in events) if minutesToRun has is used.

numberOfEvents: 1000,

delayBetweenEvents: 0.03,    // In seconds

/**

* Sometimes the monkey can fall into UI Holes from which it it is hard to escape. The monkey may then spend an inordinate

* amount of time in such holes, neglecting other parts of the application.

*

* For example, if a parent Window P has a large image

* and clicking on the image opens a child window C from which one exits by tapping a small X on the top right, then until that small X is

* tapped we will remain in C. conditionHandlers offer the developer the option to periodically recognize that we are in C and press the X.

*

* See buttonHandler.js for a specialized conditionHandler useful when a top level button can be used to escape from a UI hole.

*

* conditionHandlers are objects that respond to the following methods:

*  isTrue(target, eventNumber): returns True if the condition is true given target and event number eventNumber.

*  checkEvery(): How many events should pass before we check.

*  handle(target, mainWindow) handle the condition.

*  isExclusive() if true then if this condition‘s handler is invoked then processing subsequent conditions is skipped for this particular event. This

* is usually set to true as it allows the condition to exit a UI hole and at that point there may be no point executing other conditions

*  logStats() log statics using UIALogger;

* condition handlers must have the following property

*  statsHandleInvokedCount - the count of the number of times we were invoked

*/

conditionHandlers: [],

/**

* Unfortunately if the application is not responsive "ANR", the monkey may not notice and continue to fire events not realizing that

* the application is stuck. When run via continuous integration users may not notice that "successful" monkey runs in fact were in an

* ANR state.

*

* To deal with this the monkey supports ANR detection. Using an anrFingerprint function it periodically takes a fingerprint and if these

* are identical for a specified interval then an ANR exception is thrown.

*

*

*/

anrSettings: {

//fingerprintFunction defaults to false which will disable ANR fingerprinting. Otherwise set to a function that will return

//a string. One useful idiom using tuneup.js is

//#import tuneup.js

//config.anrSettings.fingerprintFunction = function() {return logVisibleElementTreeJSON(false)};

fingerprintFunction: false,

eventsBeforeANRDeclared: 1500, //throw exception if the fingerprint hasn‘t changed within this number of events

eventsBetweenSnapshots: 150, //how often (in events) to take a snapshot using the fingerprintFunction

debug: false //if true extra logging is made

},

// If the following line is uncommented, then screenshots are taken

// every "n" seconds.

//screenshotInterval: 5,

// Events are triggered based on the relative weights here. The event

// with this highest number gets triggered the most.

//

// If you want to add your own "events", check out the event method

// definitions below.

eventWeights: {

tap: 500,

drag: 50,

flick: 1,

orientation: 1,

clickVolumeUp: 1,

clickVolumeDown: 1,

lock: 1,

pinchClose: 10,

pinchOpen: 10,

shake: 1

},

// Probability that touch events will have these different properties

touchProbability: {

multipleTaps: 0.05,

multipleTouches: 0.05,

longPress: 0.05

},

// Uncomment the following to restrict events to a rectangular area of

// the screen

frame: {

origin: {x: 0,y: 25},

size: {width: 200,height: 400}

}

};

// Dismiss alerts

UIATarget.onAlert = function onAlert(alert) {

var title = alert.name();

UIALogger.logMessage(‘On Alert: ‘ + title);

return true;

}

}

// --- --- --- ---

// Event Methods

//

// Any event probability in the hash above corresponds to a related event

// method below. So, a "tap" probability will trigger a "tap" method.

//

// If you want to add your own events, just add a probability to the hash

// above and then add a corresponding method below. Boom!

//

// Each event method can call any other method on this UIAutoMonkey object.

// All the methods at the end are helpers at your disposal and feel free to

// add your own.

UIAutoMonkey.prototype.allEvents = {

tap: function() {

this.target().tapWithOptions(

{ x: this.randomX(), y: this.randomY() },

{

tapCount: this.randomTapCount(),

touchCount: this.randomTouchCount(),

duration: this.randomTapDuration()

}

);

},

drag: function() {

this.target().dragFromToForDuration(

{ x: this.randomX(), y: this.randomY() },

{ x: this.randomX(), y: this.randomY() },

0.5

);

},

flick: function() {

this.target().flickFromTo(

{ x: this.randomX(), y: this.randomY() },

{ x: this.randomX(), y: this.randomY() }

);

},

orientation: function() {

var orientations = [

UIA_DEVICE_ORIENTATION_PORTRAIT,

UIA_DEVICE_ORIENTATION_PORTRAIT_UPSIDEDOWN,

UIA_DEVICE_ORIENTATION_LANDSCAPELEFT,

UIA_DEVICE_ORIENTATION_LANDSCAPERIGHT

];

var i = Math.floor(Math.random() * 10) % orientations.length;

var newOrientation = orientations[i];

this.target().setDeviceOrientation(newOrientation);

this.delay(0.9);

},

clickVolumeUp: function() {

this.target().clickVolumeUp();

},

clickVolumeDown: function() {

this.target().clickVolumeDown();

},

//lock: function() {

//    this.target().lockForDuration(Math.random() * 3);

//},

pinchClose: function () {

this.target().pinchCloseFromToForDuration(

{ x: this.randomX(), y: this.randomY() },

{ x: this.randomX(), y: this.randomY() },

0.5

);

},

pinchOpen: function () {

this.target().pinchOpenFromToForDuration(

{ x: this.randomX(), y: this.randomY() },

{ x: this.randomX(), y: this.randomY() },

0.5

);

},

shake: function() {

this.target().shake();

}

};

// --- --- --- ---

// Helper methods

//

UIAutoMonkey.prototype.RELEASE_THE_MONKEY = function() {

// Called at the bottom of this script to, you know...

//

// RELEASE THE MONKEY!

if (this.config.minutesToRun && this.config.numberOfEvents) {

throw "invalid configuration. You cannot define both minutesToRun and numberOfEvents"

}

var conditionHandlers = this.config.conditionHandlers || []; //For legacy configs, if not present default to empty.

var useConditionHandlers = conditionHandlers.length > 0;

var checkTime = false;

var localNumberOfEvents = this.config.numberOfEvents; //we may modify so we want to leave config untouched

if (this.config.minutesToRun) {

checkTime = true;

localNumberOfEvents = 2000000000;

var startTime = new Date().getTime();

var checkTimeEvery = this.config.checkTimeEvery || 60; //number of events to pass before we check the time

}

//setup anr parameters as needed

var anrFingerprintFunction = this.config.anrSettings ? this.config.anrSettings.fingerprintFunction : false; //handle legacy settings missing this

if (anrFingerprintFunction) {

this.anrSnapshot = "Initial snapshot-nothing should match this!!";

this.anrSnapshotTakenAtIndex = -1;

var anrEventsBetweenSnapshots = this.config.anrSettings.eventsBetweenSnapshots || 300;

var anrDebug = this.config.anrSettings.debug;

this.anrMaxElapsedCount = -1;

}

var targetBundleId = this.target().frontMostApp().bundleID();

for (var i = 0; i < localNumberOfEvents; i++) {

if (checkTime && (i % checkTimeEvery == 0)) { //check the time if needed

var currTime = new Date().getTime();

var elapsedMinutes = (currTime-startTime) / 60000;

if (elapsedMinutes >= this.config.minutesToRun) {

UIALogger.logDebug("Ending monkey after " + elapsedMinutes + " minutes run time.");

break;

} else {

UIALogger.logDebug(this.config.minutesToRun - elapsedMinutes + " minutes left to run.")

}

}

var currentBundleId = this.target().frontMostApp().bundleID();

if (currentBundleId !== targetBundleId) {

UIALogger.logDebug("Ending monkey because it went outside of the tested app (‘" + currentBundleId + "‘)");

break;

}

this.triggerRandomEvent();

if (anrFingerprintFunction && (i % anrEventsBetweenSnapshots == 0)) this.anrCheck(i, anrFingerprintFunction, anrDebug);

if (this.config.screenshotInterval) this.takeScreenShotIfItIsTime();

if (useConditionHandlers) this.processConditionHandlers(conditionHandlers, i+1, this.target());

this.delay();

}

// publish stats if warranted

if (anrFingerprintFunction) {

UIALogger.logDebug("ANR Statistics");

UIALogger.logDebug("ANR max event count for identical fingerprint snapshots :: events before ANR declared: " + this.anrMaxElapsedCount + " :: " + this.config.anrSettings.eventsBeforeANRDeclared);

}

if (useConditionHandlers) {

UIALogger.logDebug("ConditionHandler Statistics")

conditionHandlers.forEach(function(aHandler) {aHandler.logStats()});

conditionHandlers.sort(function(aHandler, bHandler) {return aHandler.statsHandleInvokedCount - bHandler.statsHandleInvokedCount});

UIALogger.logDebug("sorted by HandleInvokedCount");

conditionHandlers.forEach(function(aHandler) {UIALogger.logDebug(aHandler + ": " + aHandler.statsHandleInvokedCount)});

}

};

UIAutoMonkey.prototype.anrCheck = function(i, fingerprintFunction, debugFlag){

var newSnapshot = fingerprintFunction();

if (newSnapshot != this.anrSnapshot) {

//all is good, we‘re moving along

if (debugFlag) UIALogger.logDebug("UIAutoMonkey:anrCheck(): snapshot != for event " + i);

this.anrSnapshot = newSnapshot;

this.anrSnapshotTakenAtIndex = i;

}

else {

//have a match

//for how many counts?

var elapsedCount = i - this.anrSnapshotTakenAtIndex;

this.anrMaxElapsedCount = Math.max(this.anrMaxElapsedCount, elapsedCount);

UIALogger.logDebug("UIAutoMonkey:anrCheck(): snapshot == with elapsed count=" + elapsedCount);

if (elapsedCount > this.config.anrSettings.eventsBeforeANRDeclared) {

UIALogger.logDebug("duplicate snapshot detected" + this.anrSnapshot);

throw "anr exception-identical after " + elapsedCount + " events";

};

};

};

UIAutoMonkey.prototype.processConditionHandlers = function(conditionHandlers, eventNumberPlus1, target) {

var mainWindow = target.frontMostApp().mainWindow(); //optimization to let handlers do less work. Assumes isTrue() doesn‘t alter the mainWindow.

for (var i = 0; i < conditionHandlers.length; i++) {

var aCondition = conditionHandlers[i];

if ((eventNumberPlus1 % aCondition.checkEvery()) != 0) {

continue; //not yet time to process aCondition.

}

try {

UIATarget.localTarget().pushTimeout(0);

var isConditionTrue = aCondition.isTrue(target, eventNumberPlus1, mainWindow);

}

finally {

UIATarget.localTarget().popTimeout();

}

if (isConditionTrue) {

aCondition.handle(target, mainWindow);

if (aCondition.isExclusive()) {

break;

} else {

mainWindow = target.frontMostApp().mainWindow(); //could be stale

}

};

};

};

UIAutoMonkey.prototype.triggerRandomEvent = function() {

var name = this.chooseEventName();

console.log(‘outputeventname‘,name);

// Find the event method based on the name of the event

var event = this.allEvents[name];

console.log(‘outputevent‘,event);

if(typeof(event)!="undefined"){

event.apply(this)

};

};

UIAutoMonkey.prototype.target = function() {

// Return the local target.

return UIATarget.localTarget();

};

UIAutoMonkey.prototype.delay = function(seconds) {

// Delay the target by `seconds` (can be a fraction)

// Defaults to setting in configuration

seconds = seconds || this.config.delayBetweenEvents;

this.target().delay(seconds);

};

UIAutoMonkey.prototype.chooseEventName = function() {

// Randomly chooses an event name from the `eventsWeight` dictionary

// based on the given weights.

var calculatedEventWeights = [];

var totalWeight = 0;

var events = this.config.eventWeights;

for (var event in events) {

if (events.hasOwnProperty(event)) {

calculatedEventWeights.push({

weight: events[event]+totalWeight,

event: event

});

totalWeight += events[event];

}

}

var chosenWeight = Math.random() * 1000 % totalWeight;

for (var i = 0; i < calculatedEventWeights.length; i++) {

if (chosenWeight < calculatedEventWeights[i].weight) {

return calculatedEventWeights[i].event;

}

}

throw "No even was chosen!";

};

UIAutoMonkey.prototype.screenWidth = function() {

// Need to adjust by one to stay within rectangle

return this.target().rect().size.width - 1;

};

UIAutoMonkey.prototype.screenHeight = function() {

// Need to adjust by one to stay within rectangle

return this.target().rect().size.height - 1;

};

UIAutoMonkey.prototype.randomX = function() {

var min, max;

if (this.config.frame){

// Limits coordinates to given frame if set in config

min = this.config.frame.origin.x;

max = this.config.frame.size.width + min;

} else {

// Returns a random X coordinate within the screen rectangle

min = 0;

max = this.screenWidth();

}

return Math.floor(Math.random() * (max - min) + min) + 1;

};

UIAutoMonkey.prototype.randomY = function() {

var min, max;

if (this.config.frame){

// Limits coordinates to given frame if set in config

min = this.config.frame.origin.y;

max = this.config.frame.size.height + min;

} else {

// Returns a random Y coordinate within the screen rectangle

min = 0;

max = this.screenHeight();

}

return Math.floor(Math.random() * (max - min) + min) + 1;

};

UIAutoMonkey.prototype.randomTapCount = function() {

// Calculates a tap count for tap events based on touch probabilities

if (this.config.touchProbability.multipleTaps > Math.random()) {

return Math.floor(Math.random() * 10) % 3 + 1;

}

else return 1;

};

UIAutoMonkey.prototype.randomTouchCount = function() {

// Calculates a touch count for tap events based on touch probabilities

if (this.config.touchProbability.multipleTouches > Math.random()) {

return Math.floor(Math.random() * 10) % 3 + 1;

}

else return 1;

};

UIAutoMonkey.prototype.randomTapDuration = function() {

// Calculates whether or not a tap should be a long press based on

// touch probabilities

if (this.config.touchProbability.longPress > Math.random()) {

return 0.5;

}

else return 0;

};

UIAutoMonkey.prototype.randomRadians = function() {

// Returns a random radian value

return Math.random() * 10 % (3.14159 * 2);

};

UIAutoMonkey.prototype.takeScreenShotIfItIsTime = function() {

var now = (new Date()).valueOf();

if (!this._lastScreenshotTime) this._lastScreenshotTime = 0;

if (now - this._lastScreenshotTime > this.config.screenshotInterval * 1000) {

var filename = "monkey-" + (new Date()).toISOString().replace(/[:\.]+/g, "-");

this.target().captureScreenWithName(filename);

this._lastScreenshotTime = now;

}

};

// If you want to control when the monkey is released please follow the pattern in the SampleCustomization folder. In brief you want to set a global

// as set in SetGlobals.js, but due to Apple‘s javascript implementation you cannot simply set it before you import UIAutoMonkey.js.

//

if (typeof UIAutoMonkeyClientWillReleaseTheMonkey == ‘undefined‘ || !UIAutoMonkeyClientWillReleaseTheMonkey) {

// the variable is not defined or it‘s defined and false

UIALogger.logDebug("Releasing the monkey directly from UIAutoMonkey"); //explain why it was released to aid in problem resolution.

(new UIAutoMonkey()).RELEASE_THE_MONKEY();

}

时间: 2024-11-05 14:39:52

ui automonkey的相关文章

(一)UI AUtoMonkey:xcode 里直接执行monkey

最直接简单的一种在ios应用上运行monkey的方式--在xcode使用自带的工具instruments--automation (UI AUtoMonkey): 方法如下: 一.连接真机,或使用模拟器: 二.在xcode下菜单下,点击 Product --Profile,自动将项目的 Appdebug包 安装到 模拟器或连接的真机上: 三.在弹出的 框中选择 automation: 四.打开运行界面,如下图所示,进行选择 (设备.待测APP.使用script方式执行monkey ) 五.红框处

IOS 压力测试-UI AutoMonkey

UI AUtoMonkey是一款非常简单的IOS压力测试工具.通过它,你可以向ios设备发送滑动.拖动.旋转.甚至锁屏和解锁指令.原文github地址:https://github.com/jonathanpenn/ui-auto-monkey 如果你的mac电脑已经安装了xcode,那么环境就已经ok了,xcode中已经自带了UI Automation和Instruments.跟着下面的步骤进行操作就可以使用UIAutomonkey.js这个js脚本,进行monkey测试. 1.首先,用Xco

iOS--(monkey)测试--UI AUtoMonkey

阅读目录 安装 额外配置 UI AutoMonkey UI AUtoMonkey是一款非常简单的IOS压力测试工具.通过它,你可以向ios设备发送滑动.拖动.旋转.甚至锁屏和解锁指令.原文github地址:https://github.com/jonathanpenn/ui-auto-monkey 安装 如果你的mac电脑已经安装了xcode,那么环境就已经ok了,xcode中已经自带了UI Automation和Instruments.跟着下面的步骤进行操作就可以使用UIAutomonkey.

APP压力測试新手教程

Daniel Knott 用过各种不同编程语言和软件质量保证工具.他在软件开发和測试方面干了七年,自2010年,他一直在德国汉堡的XING AG公司就职,几个项目里,比方XING调查和XING建议,他负责測试管理,測试自己主动化和測试运行.Daniel如今是XING移动和XING API团队的质量保证团队领导.在XING移动团队里,他还是负责XING安卓和iPhone Apps的測试管理和測试自己主动化.Daniel在包含像Robotium, KIF (Keep It Functional),

APP压力测试入门教程

? Daniel Knott 用过各种不同编程语言和软件质量保证工具.他在软件开发和测试方面干了七年,自2010年,他一直在德国汉堡的XING AG公司就职,几个项目里,比如XING调查和XING建议,他负责测试管理,测试自动化和测试执行.Daniel现在是XING移动和XING API团队的质量保证团队领导.在XING移动团队里,他还是负责XING安卓和iPhone Apps的测试管理和测试自动化.Daniel在包括像Robotium, KIF (Keep It Functional), Se

autoMonkey框架介绍

http://note.youdao.com/noteshare?id=fb942e6a61f94224c24182fa3578d035&sub=B04EA08F00C5477EA75C7162E68F5BE5 题记 为什么要搞 Monkey aotoMonkey 是什么 Monkey 运行篇 Monkey 日志分析篇 Monkey 问题处理篇 Monkey 数据上报篇 Monkey 数据分析篇 写在最后 第一部分[题记] autoMonkey是我在上一家公司自己搞的基于Android Monk

基于jquery开发的UI框架整理分析

根据调查得知,现在市场中的UI框架差不多40个左右,不知大家都习惯性的用哪个框架,现在市场中有几款UI框架稍微的成熟一些,也是大家比较喜欢的一种UI框架,那应该是jQuery,有部分UI框架都是根据jQuery研发出来的产品,现在也很常见了. 国产jQuery UI框架 (jUI) DWZ DWZ富客户端框架(jQuery RIA framework), 是中国人自己开发的基于jQuery实现的Ajax RIA开源框架.设计目标是简单实用,快速开发,降低ajax开发成本. jQuery 部件布局

iOS instruments之ui automation的简单使用(高手绕道)

最近使用了几次instruments中的automation工具,现记录下automation的简单使用方法,希望对没接触过自动化测试又有需求的人有所帮助.  UI 自动测试是iOS 中重要的附加功能,它由名为"Automation"的新的工具对象支持.Automation工具的脚本是用JavaScript语言编写,主要用于分析应用的性能和用户行为,模仿/击发被请求的事件,利用它可以完成对被测应用的简单的UI测试及相关功能测试. 一. 简单的录制脚本 打开xcode,这里用我为我家亲爱

RDVECore来自锐动的无UI,高度抽象化API的视频编辑SDK--IOS版

1 编写目的 预期读者: 有视频编辑开发经验或者无经验的,打算或者正在使用"锐动IOS版RDVECore"的相关工程师. iOS软件工程师. 产品经理. QA 2 名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1080x720,640x480等. 帧率:每秒的帧数(fps)或者说帧率表示图形处理器处理场时每秒钟能够更新的次数. 码率: 数据传输时单位时间传送的数据位数,一般我们用的