MonkeyTalk 【翻译原创】(二)MonkeyTalk 语言参考说明

water · 2014年12月23日 · 最后由 Haibo 回复于 2015年09月13日 · 2406 次阅读
本帖已被设为精华帖!

注: MonkeyTalk 脚本语言是简单而强大的,此说明书中详细说明了很多用法,由于内容比较多,未翻译完的地方会后续有时间补充。

概论:
MonkeyTalk 是由用户层面的一系列简单命令组成的多功能测试语言。它足够简单地给测试人员使用,并且几乎不需要开发功底来进行分析,同时也可以给那些需要进一步编程的人员无缝地使用 Java Script 来编写。脚本可以由简单到由 txt 文档直接编写,或者由 MonkeyTalk IDE 等录制工具直接生成。
MonkeyTalk 语言是与平台无关的,并且提供了标准的 API,可以由任何一种编程语言来实现。MonkeyTalk 1.0 中包含捆绑了 Java Script 语言。

命令语法:
它语法设计的出发点是让非开发人员也能轻易地看懂。它可读性高,可以使用简单的 txt 文本编辑器甚至表格来简单明了地阅读。另外,MonkeyTalk 设计成可以用扁平表格编辑器例如 MonkeyTalk IDE 来进行阅读和编辑。
MonkeyTalk 是一行作为一个一个命令的开始和结束,每一行遵从如下语法:
组件类型 MonkeyID 动作 各种参数... 修改器...
(ComponentType MonkeyId Action Args… Modifiers…)
总体说来,组件类型、MonkeyId、动作、参数、修改器合在一起构成命令的各个部分,组件类型所包含的动作就是这条命令的名字。
下面是各部分的说明:
1, 组件类型(必填):动作执行所在的组件的类型。例如按钮 (Button) 或文本框 (TextArea)。组件类型是大小写不敏感的。组件类型可以扩展其他的组件类型,正如下面所说,还可以继承任何已定义的方法及其参数。组件类型是代表了 UI 组件的逻辑名字(例如叫 Button 而不叫 UIButton),但也可以是特定平台的别名。所有的 UI 组件都继承自 View 类型的组件,所以当你指定 View 作为组件类型时就像使用通配符匹配所有类型的组件,例如:

# 点击带有"OK"标签的任何组件
View OK Tap 

2,MonkeyId(必填):一个用来区分同一页面上同时显示的相同组件类型的不同组件标示。MonkeyId 可以使用星号()表示识别到的第一个匹配类型的组件。
MonkeyId 也可以规定用从 1 开始 (不是从 0 开始) 的引索以 #N 的格式来表示。这种情况下,MonkeyId 标志了显示页面中的第 N 个匹配类型的组件。组件引索的顺序是按照坐标 (x, y) 从上到下、从左到右的进行排序的。
3,动作(必填):就是要执行的动作。例如包括 Tap, Select, 和 EnterText 等。动作 (Action) 是大小写不敏感的。
4,参数(按组件类型和动作需要填写):是一个或多个由空格隔开的列表。参数默认是从整条命令的第四列 (第四部分) 开始的。尽管它是以 String 类型表现,解读的时候是由命令的需要来进行解读的。如果某个参数是必须的但是没有填写(少写了最后一个参数),它就会使用默认值。参数可以使用星号(
)来强制使用它默认值。
5,修改器(选填):以空格隔开的、以%name=value 格式表示的参数列表,% 前缀用来标示它是一个修改器。有三个系统定义的修改器:
%timeout - 等待多少毫秒超时,超时之前重复尝试执行命令
%thinktime - 尝试执行第一次命令时的等待时间(毫秒)
%retrydelay - 再次多次尝试执行命令之间的间隔时间(毫秒)。(注:如果执行不成功就会继续尝试直到超时,例如页面还没刷新找不到组件)

命令举例:
所有的列都是以空格隔开的。带空格的值一定要用引号引起来。表示引号本身需要在双引号内用反斜杠转义,来表示引号本身。
点击 OK 按钮:

Button OK Tap

点击页面上的第二个按钮:

Button #2 Tap

点击页面上的第一个按钮:

Button * Tap

或者 Button #1 Tap
点击页面上的第一个控件:

* * Tap

传入参数带空格:

TextArea editText1 enterText “this is a test

设置动作超时时间为 5 秒

TextArea editText1 enterText “this is a test” %timeout=5000

注释是以 # 开头

# this is a comment
# another comment
Button OK Tap

换行用\n 表示

Input shipping EnterText “John Smith\n123 Main St.\nAnytown, USA 12345”

脚本:
把一条或者多条 MonkeyTalk 命令放到一个文件中并保存为.mt 文件你就得到了一个 MonkeyTalk 脚本。
举个例子,一个登陆的.mt 脚本可能看起来是这样的:

# simple script to login as joe
Input username EnterText joe-at-doe.com
Input password EnterText “i like cheese”
Button LOGIN Tap

想在脚本中调用另一个脚本,可以使用 Script 命令加上.mt 文件名作为 MonkeyId,就像这样:Script login.mt Run

变量:
脚本中可以包含写法为 ${name} 的变量,并且可以在一条命令的任何地方使用。也可以包含写法类似于 ${var}的内置变量。
内置变量有 %{componentType}, %{monkeyId}, %{action}以及内置参数 %{1}, %{2}等等。变量只能作为命令的某一部分,包括组件类型、MonkeyId 等等。
例如,一个已命名的变量可以作为参数:

Input username EnterText ${usr}

或者参数和 MonkeyId:

Input ${foo} EnterText ${bar}

又或者整条命令都用参数:

${foo} ${bar} ${baz}

变量可以内嵌到某些字符串里面,但是不能内嵌到另一个变量名中,例如:

Input username EnterText ${usr}@example.com

但是下面这样的命令是不合法的:

Input username EnterText ${foo${bar}}

参数化脚本:
使用 Vars.Define 命令可以在脚本中命名变量并设置它们的默认值。让我们参数化我们的 Login.mt 脚本如下:

Vars * Define usr="default-at-example.com" pwd
Input username EnterText ${usr}
Input password EnterText ${pwd}
Button LOGIN Tap

我们设置了两个变量 ${usr} 和 ${pwd},并设置 ${usr}的默认值为 default-at-example.com。${pwd}变量的默认值没有指定,所以默认值会是(以尖括号括起来的变量名)。
我们可以用如下方式调用我们的参数化脚本:

Script login.mt Run joe-at-doe.com "i like cheese"

或者让脚本参数使用默认值:

Script login.mt Run

或者使用一个星号来使用 ${usr}的默认值:

Script login.mt Run * password1

请注意变量只能在定义它们的脚本中使用,所以 ${usr} 和 ${pwd}只在 login.mt 中有定义。当然除非你使用变量来调用一个子脚本。

数据驱动脚本:
参数化脚本只是一个开始,MonkeyTalk 支持全数据驱动的脚本,仅仅只要使用 RunWith 代替 Run 命令,并且设定一个数据文件作为第一个参数。
用我们的参数化脚本 login.mt 举例,我们首先编写一个数据文件 credentials.csv,用 csv 格式保存如下:

joe-at-doe.com, "i like cheese"
alpha-at-beta.net, password1
charlie-at-dog.org, abc123

第一行可以指定变量名(与 login.mt 脚本最前面的 Vars.Define 中他们命名完全相同),后面各行指定变量值。MonkeyTalk 需要 CSV 文件每一列以逗号隔开,如果带空格需要用双引号引起来。
现在,我们可以数据驱动我们的脚本:

Script login.mt RunWith credentials.csv

这会根据数据文件中的每一行数据跑一边 login.mt 脚本。所以这个例子中 login.mt 会运行 3 此,第一次运行时参数 usr = joe-at-doe.com 和 pwd = "i like cheese",第二次 usr = alpha-at-beta.net 和 pwd = password1,第三次 usr = charlie-at-dog.org 和 pwd = abc123。

RunIf 命令:
使用 RunIf 命令,我们可以指定一个命令通过以后才跑某一个脚本。使用这条命令的方法是在一个带有 Verify 的命令执行通过以后跑指定一个脚本,使用命令如下:

Script YourScript.mt RunIf [Verify Command]

这意思是你在参数部分把脚本中的其他命令整个放在了里面。一个脚本例子如下:

Input username enterText Fred
Input password enterText SecurePassword
Button LOGIN tap 
script logout.mt RunIf Label * Verify "Welcome, Fred!"

自定义命令:
MonkeyTalk 语言可以通过自定义部件类型 (component type) 和动作 (Action) 来进行拓展。任何以两个部分组成,格式为..mt 命名的脚本自动可以作为自定义命令。例如,如果我们创建了一个名为 user.login.mt 的脚本,我们就可以增加一个 user 的部件类型,它拥有 login 的动作。
我们用以下的样式来调用新的自定义命令:

User * Login

并且我们可以传递 MonkeyId 以及参数:

User joe Login joespassword

在你自定义的命令中,可以使用%{monkeyId}的格式来使用传进来的 monkeyId。下面是一个可以实现上面命令的 user.login.mt 脚本的例子:

Vars * Define pwd="password"
Input username enterText %{monkeyId}
Input password enterText ${pwd}
Button LOGIN tap

测试和验证:
一个测试 (Test) 就是使用 Test 部件来代替 Script 部件进行调用一个脚本。测试结果会写到一个标准的文件中,以 JUnit-compatible xml 文件格式保存。
每条命令的执行成功与否在于验证用户指定的界面部件 (元素) 是否存在。另外,你也可以在脚本中使用 Verify 动作来验证部件中的值是否与预期一致。首先,我们再次重写 login.mt,加入一些 Verify 动作,像这样:

Vars * Define usr="default-at-example.com" pwd=name
Input username EnterText ${usr}
Input password EnterText ${pwd}
Button LOGIN Tap
Label welcome Verify "Welcome, ${name}!"
Button LOGOUT Verify

现在,我们可以以如下方式测试 (Test) 的方式来运行 login.mt,值得注意的是,我们增加了 ${name}这个变量,因此我们需要加入第三个参数进行调用:

Test login.mt Run joe-at-doe.com "i like cheese" "Joe Doe"

并且我们也可以使用数据驱动的方式来测试我们的脚本(注意增加第三列的数据到 credentials.csv)

Test login.mt RunWith credentials.csv

验证 (Verify):
Verify 动作存在于所有的部件中(除了 Script 和 Device),用以验证实际的值是否是我们想要的值。在它的基本格式中,Verify 接受三个可选参数:expectedValue, propPath, 以及 failMessage。
如果没有传递任何参数,Verify 只验证部件是否存在:

Button LOGIN Verify

当只有一个 expectedValue 参数时,Verify 会检查部件中的值,这些值只会是部件逻辑上的值(Button 的值是它的 label,Input 的值是它的 text,CheckBox 的值是"On"或者"Off",等等):

Button LOGIN Verify LOGIN

用 expectedValue 以及 propPath 作为参数时,Verify 会检查制定的部件属性。一些 propPaths 例如 value 或 item 是逻辑上 MonkeyTalk 指定的属性路径,它们是跨平台的(它们不以点作为开头)。部件指定的属性值是平台相关的(它们以点作为开头)。
验证一个 iOS 按钮的 Font 名字:

Button LOGIN Verify Helvetica .font.fontName

验证 Android 上 RatingBar 总的星星数量:

RatingBar reviewRating Verify 5 .numStars

最后一个参数时验证失败时给出的信息 failMessage :

Input username Verify joe-at-doe.com value "bad username!!!"

可以在用户手册上查看更详细内容:
http://www.cloudmonkeymobile.com/monkeytalk-documentation/monkeytalk-user-guide/verifying-expected-values/using-verification-commands

测试套件 (Suite)
一个测试套件 (Suite) 就是若干脚本的 Test 放在一起执行的集合。当一个 Test 失败时,它不会立刻停止,而是跑下一个 Test。当所有的 Test 执行完毕时,会生成一个 xUnit-compatible 的报告 (http://reflex.gforge.inria.fr/xunit.html#xunitReport), 报告会统计所有所跑 Test 的 Pass 数、Fail 数、Error 数。
Suite 必须以.mts 文件后缀结尾,与脚本区别开来。
Suite 使用 Test 命令调用脚本,以"Test"作为部件类型,脚本名称作为 monkeyId,Run 或者 Runwith 作为动作 (action)。一个 Test 命令(在 Suite 中使用)与 Script 命令(在 Scripte 中使用)类似;它只是增加了一些额外的管理功能。例如一个简单的 Suite 如下:

# login and log out
Test login.mt Run joe@doe.com JoEsPaSsWoRd
Test logout.mt

只有在 Suite 中可以使用 Test 命令,相反只有脚本中可以使用 Scipt 命令。一般来说,如果你想要跑一个脚本,就在 Suite 中调用 Tests,在脚本中调用 Script。
有时候一组 Test 会共享一些依赖及清理工作,在每个 Test 前后进行维护时非常无聊并且容易出错的。Suite 允许你使用"Setup"以及"Teardown"部件类型来进行设置初始化及清理工作(分别在每一条 Test 前后执行),用法与 Test 命令非常类似。在 Suite 中,任何这样定义的 Setup 脚本都会在没一个 Test 前进行调用,如果初始化成功,Test 就会运行,然后 Teardown 就会运行(无论 Test 成功与否)。
Suite 里面可以调用其他的 Suite,使用 Suite 部件类型。
Suite 中只能包含 Test, Setup, Teardown, 和 Suite,以及注释。
举个例子,一个 myapp.mts 测试套件可能长这样:

# setup runs before every test
Setup login.mt Run joe@doe.com JoEsPaSsWoRd

# teardown runs after every test
TearDown logout.mt Run

# the tests...
Test add_contact.mt RunWith contacts.csv
Test remove_contact.mt RunWith contacts.csv

例子中我们就使用 Setup 和 TearDown 来指定每条 Test 执行前后需要调用的脚本。

命令执行选项:
除非特殊指定,否则 MonkeyTalk 在超时时间之前会不停地尝试去执行命令。超时时间的值有一个为 2 秒的全局默认值,也可以在每一条语句后面使用超时的编辑器 (Modifier) 来自定义。
例如:

Button OK Tap %timeout=5000 %thinktime=2000 %retrydelay=123

上述命令会在尝试点击 OK 按钮之前等待 2 秒钟,然后每隔 123 毫秒会尝试一次执行命令,直到 5 秒的超时时间到。(命令最多会执行 7 秒钟)。

注:后面的一些内容为介绍 Java Script 语法、Java API、命令大全的内容,太多就不翻译了。有兴趣的童鞋可以访问连接查看:
http://www.cloudmonkeymobile.com/monkeytalk-documentation/monkeytalk-language-reference/scripting-javascript

到这里语法说明终于告一段落。由于最近比较懒,更新也是断断续续的,语法说明篇幅大概在 4000 字左右,请期待下一篇- 3-

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 11 条回复 时间 点赞

Monkeytalk 语法简明,初学者用起来比较方便,IDE 做的比较烂,经常崩溃。

#1 楼 @squallff 我用的时候目前没有崩溃过,你试试别用 Pro 版本? 可以脱离 IDE 写脚本,用 Excel 写都可以 - -!

第二篇了,加油!~

#3 楼 @pajack 你的单元测试学的咋样?

@weamylady 没进展,先学习下 Android 代码~

#2 楼 @weamylady 我用的不是 pro 的,就是普通版。复杂的逻辑用 mt 语言写不了,只能用 js 写。扩展性不强。后来我们用 MT 提供的 jar 包做了个框架,写起来就顺手多了。

#6 楼 @squallff 那是技术测试人员的思维惯性,一条一条单独的案例为何需要这么复杂的逻辑语言呢?一个案例整个流程下来应该是单线的,Pass 就是 Pass,Fail 就是 Fail。当然我同意 Java API 来编写顺手一点,自由性和逻辑性强很多,MonkeyTalk 语言的简单的好处就是容易给编程功底弱的测试人员使用,容易推广,毕竟要你写所有案例的脚本太累了。

#6 楼 @squallff 普通版本容易崩溃就用 Pro Beta 版本试试。

#1 楼 @squallff 我用的也没崩溃过

#8 楼 @weamylady 可能大家都是在 windows 系统上用的吧,我是 OSX 系统

@weamylady 大神最近还有在研究 MonkeyTalk 吗,可以跟你交流学习一下吗?

1楼 已删除
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册