上次介绍iQuery之后,已经有些朋友在开始在手机自动化测试程序里试用iQuery了,由于之前的介绍文档比较含糊,先搁置扩展iQuery使其支持多种编程语言的系列文章,补充一下iQuery的入门教程,之前写的介绍性文章可以参考:
1. 开源类库iQuery Android版使用说明
2. 类jQuery selector的控件查询iQuery开源类库介绍
3. 开源手机自动化测试框架iQuery入门教程(一)
iQuery是一个开源的自动化测试框架项目,有兴趣的朋友可以在这里下载:https://github.com/vowei/iQuery/downloads
源码位置:https://github.com/vowei/iQuery
在iQuery里增加新的伪类
在前文开源类库iQuery Android版使用说明提到,iQuery语法包含有伪类、伪属性等概念,我们编写iQuery的一个主要目标就是对测试人员隐藏多平台上查找控件的差异性,而伪类和伪属性就是隐藏不同平台上控件差异性的核心方式,然而我们在开发iQuery的时候,只提供了少数几个伪类:
:button – 代表按钮控件,在不同的移动操作系统上,iQuery会将button这个伪类转换相应的按钮控件。
:checkbox – 代表复选框控件。
:radio – 代表单选框控件。
:text – 代表文本编辑框控件。
:label – 代表文本标签控件。
:image – 代表图片控件。
这样做的目的是想保持iQuery的简洁性,同时iQuery也提供了方法让用户测试开发工程师注册自定义的伪类。
比如说要注册一个新的伪类“:switch”,这个伪类在iOS平台上,代表“UIASwitch”类型的控件,在Android平台上,代表“CheckBox”控件,注册的方式如下:
Android:
iQueryParser parser = iQuery.createParser(“:switch”); parser. registerPseudoClass(“switch”, new IPseudoClass() { public boolean resolve(ITreeNode node) { return filterByNameEndsWith(node, "CheckBox"); } });
在上例中,第一行首先创建一个iQueryParser对象,使用iQuery.createParser(String iquery)这个函数创建,如果看源码可知,由这个函数创建的iQueryParser对象会注册默认的伪类。第2行之后,通过iQueryParser.registerPseudoClass对象注册伪类,该函数接受一个字符串参数 – 要注册的伪类名,第二个参数是一个实现了IPseudoClass的对象,是一个回调函数,当iQueryParser碰到非默认的伪类时,会调用这个函数判断一个UI控件对象是否归属于这个伪类。
iOS:
var iq = new iQuery(“:switch”, true); iq.parser. registerPseudoClass(“switch”, function(uiaobj) { return isMatch(uiaobj, new Array(“UIASwitch”)); });
跟Android版类似,第一行先创建一个iQuery对象,然后在第二行通过iQuery.parser实例变量的registerPseudoClass函数注册一个伪类,和判断控件是否属于该伪类的回调函数。
在iQuery里增加新的伪属性
跟伪类相似,iQuery默认仅仅支持很少的伪属性:
[:top] – 表示一个控件的左上角的y坐标值。
[:left] – 表示一个控件的左上角的x坐标值。
[:bottom] – 表示一个控件的右下角的y坐标值。
[:right] – 表示一个控件的右下角的x坐标值。
[:width] – 表示一个控件的宽度。
[:height] – 表示一个控件的高度。
如果要注册一个新的伪属性,例如要注册一个表示控件上文本的伪属性:“:text”,在Android平台上,对于一些控件,例如按钮(Button)控件,表示其“mText”属性,而在iOS上,则是按钮控件的“name”属性。下面是注册伪属性的方法:
Android:
iQueryParser parser = iQuery.createParser(“:switch”); parser. registerPseudoAttribute (“text”, new IPseudoAttribute () { public String resolve(ITreeNode node) { return node.getProperty("mText").getValue(); } });
在上例中,第1行跟伪类相似,第2行后使用iQueryParser. registerPseudoAttribute函数注册一个新的伪属性“text”,iQueryParser通过调用一个IPseudoAttribute接口类型的回调函数来获取伪属性的值。
iOS:
var iq = new iQuery(“:switch”, true); iq.parser.registerPseudoAttrs("text", function(uiaobj) { if ( uiaobj != undefined && uiaobj.rect != undefined ) { return uiaobj.name(); } });
在上例中,第1行创建一个iQuery解析器,第二行注册“text”伪属性,和返回伪属性值的回调函数。
为了简单起见,伪属性要求返回的属性值是字符串格式,而iQuery解析器在执行属性值对比时,会根据给出的查询上下文做相应的转换。比如说:
1. 针对查询语句:
“[:text = ‘abc’]”
由于:text返回的属性值是字符串格式,而对比的期望值也是字符串格式:“’abc’”,因此通过普通的字符串对比来完成过滤操作。
详情请参看源代码:
https://github.com/vowei/iQuery/blob/master/iOS/lib/iQuery.g 中对“'[' ':' attr=ELEMENT op v=QUOTED_STRING ']'”的处理,本文写作时,为源代码的“184 - 219”行。
https://github.com/vowei/iQuery/blob/master/java/iquery/iquery-core/src/main/java/cc/iqa/iquery/iQuery.g 中对“'[' ':' attr=ELEMENT op v=QUOTED_STRING ']'”的处理,本文写作时,为源代码的“388 - 424”行。
2. 而针对查询语句:
“[:top = 123]”
虽然:top返回的属性值是字符串格式,由于对比的期望值是数字格式:“123”,因此在对比时,iQuery会将:top返回的字符串格式的属性值转化成数字,然后再做对比。
详情请参看源代码:
https://github.com/vowei/iQuery/blob/master/iOS/lib/iQuery.g 中对“'[' attr=ELEMENT num_comp_op v=(INTEGER | FLOAT | PERCENTAGE) ']'”的处理,本文写作时,为源代码的“257 - 293”行。
https://github.com/vowei/iQuery/blob/master/java/iquery/iquery-core/src/main/java/cc/iqa/iquery/iQuery.g 中对“'[' attr=ELEMENT num_comp_op v=(INTEGER | FLOAT | PERCENTAGE) ']'”的处理,本文写作时,为源代码的“425 - 479”行。
3. 但是对于查询语句:
“[:text = 123]”
由于:text返回的是字符串格式,而期望值“123”是一个数字格式,iQueryParser无法将:text的值转换成数字,因此可能会报错。
对于iQuery对伪类和伪属性的扩展就暂时讲到这里,后文讲解避免重复注册伪类和伪属性的方法。