如何测试 Android 应用程序

要对 Android AUT 进行测试,需要以下这些

  1. 可通过adb查看的运行中的Android系统,
  2. 一个用于测试的应用程序,称为测试用例(AUT),以及
  3. 一个练习AUT的测试脚本。

当Squish启动AndroidAUT时,它使用一个名为androidobserver的程序,建立连接到正在运行和部署的AUT的附加端口。

注意:对于Android设备,确保设备连接到您的PC后启用USB调试。这通常需要首先在设备上启用开发者选项,然后再在设置中看到该选项。

注意:针对Android上的Qt应用程序,请参阅安装Squish/Qt进行Android测试

API访问

Java API访问适用于由Squish启动的应用程序,无论是使用ApplicationContext startApplication(autName)还是结合使用androidobserverApplicationContext attachToApplication(autName)。对于Android桌面和其他应用程序,如果Android OS版本为4.3或更高,Squish可以调用通过Android无障碍框架可用的对象上的触摸和键盘操作。

Squish的Android对象API允许您查找和查询对象,调用方法,并访问属性

此外,Android便利API提供了执行常见用户界面操作的功能,例如在按钮上轻触或在文本小部件中输入文本。Java对象以包装的形式提供,底层的对象属性和方法可通过Squish添加的nativeObject属性访问。

如何与无障碍对象合作

对于某些测试,可能需要更改全局设置。其他测试可能需要启动第三方应用程序,该应用程序无法使用Squish仪器化或使用无障碍框架。

Squish无法直接在它未仪器化或启动的应用程序中的对象上记录。但是,如果您在记录时使用远程控制对话框作为Android设备的显示器,则将对提供的无障碍用户界面节点记录操作。Android OS版本必须为4.3或更高。

与应用内对象名称一样,请优先考虑具有独特文本、资源名称或描述的对象。同时,当播放触摸操作无效时,请参阅UiAutomator支持。

squishide可以帮助获取对象名称。当squishide在断点或记录暂停时,如果Squish仪器化的应用程序不可见,则在应用程序对象视图中将显示一个额外的顶层元素,通常是AccessiblePanel类型。因此,通过上下文菜单,可以复制对象名称。

"Application Objects context menu"

名为UI浏览器的对象快照查看器可能有助于找到特定的无障碍对象。在应用程序对象视图中右键单击无障碍对象。选择保存对象快照,包括屏幕截图和对象名称,并在随后的对话框中选择保存后打开快照浏览器。在查看器的Android UI图形表示中,单击所需的对象。然后在左侧的分层视图中右键单击所选的项目,然后选择复制真实名称

"Copy real name menu item"

对于以下对象快照,请确保保存后不在浏览器中打开快照选项未选中。当对象快照输出文件在磁盘上发生变化时,查看器将自动更新其内容。

注意:每次屏幕内容更改时,务必刷新应用程序对象视图。

以下示例脚本片段按下主页按钮,打开设置应用,等等。为了强调对象名称的差异,显示多属性名称,但进行了缩写。

goHome()
tapObject(waitForObject("{... description='Apps' type='Clickable' ...}"))
tapObject(waitForObject("{... text='Settings' type='Clickable' ...}"))
tapObject(waitForObject("{... text='Accounts' type='AccessibleLabel' ...}"))
tapObject(waitForObject("{... text='Add account' type='AccessibleLabel' ...}"))
tapObject(waitForObject("{... text='Exchange' type='AccessibleLabel' ...}"))
type(waitForObject("{... type='Editable' ...}"), "[email protected]")

只有一台Android仪器可以访问Android UIAutomation框架。如果Squish测试脚本应该访问多个应用,那么除了一个之外,所有的工作应用都应该使用–no-ui-automation启动器选项启动。例如:

startApplication("{no-ui-automation}:com.froglogic.addressbook")

如何使用nativeObject属性

nativeObject属性提供了访问Java对象的方法和属性的权限。例如,要更改Android按钮的文本,我们首先会获取按钮对象的引用,然后调用setText方法。

button = waitForObject(":Okay_Button")
button.nativeObject.setText("Cancel")
var button = waitForObject(":Okay_Button");
button.nativeObject.setText("Cancel");
my $button = waitForObject(":Okay_Button");
button->nativeObject->setText("Cancel");
button = waitForObject(":Okay_Button")
button.nativeObject.setText("Cancel")
set button [waitForObject ":Okay_Button"]
invoke $button setText "Cancel"

以下示例将Java对象方法(在本例中为按钮小部件)的方法名写入Squish日志。

buttonclass = button.nativeObject.getClass()
methods = buttonclass.getMethods()
for method in methods:
    test.log("Button method: " + method.getName())
var buttonclass = button.nativeObject.getClass();
var methods = buttonclass.getMethods();
for (i = 0; i < methods.length; ++i)
    test.log("Button method: " + methods.at(i).getName());
my $buttonclass = button->nativeObject->getClass();
my @methods = buttonclass->getMethods();
foreach $method (@methods) {
    test.log("Button method: " . $method->getName());
}
buttonclass = button.nativeObject.getClass()
methods = buttonclass.getMethods()
for method in methods:
    test.log("Button method: " + method.getName())
end
set buttonclass [invoke [property get $button nativeObject] getClass]
set methods [invoke $buttonclass getMethods]
foreach method $methods {
    set name [invoke $method getName]
    test.log("ListView method: $name")
}

最后,访问静态属性的示例。

test.log("Value of View.INVISIBLE is " + Native.android.view.View.INVISIBLE)
test.log("Value of View.INVISIBLE is " + Native.android.view.View.INVISIBLE);
test->log("Value of View.INVISIBLE is " . Native::android::view::View->INVISIBLE);

如何使用GestureBuilder类

此类的实例由readGesture(gesture-file)返回。然而,当所记录的手势不适合目标设备或模拟器的屏幕时,可以进行缩放或平移。

获取屏幕度量信息可能很有用。以下是如何使用JavaScript绑定获取屏幕大小的示例。这些度量以像素为单位,因此包括转换为毫米,以匹配在GestureBuilder对象中的点。

var activity = findObject(":Your_Activity").nativeObject;
var metrics = activity.getClass().forName("android.util.DisplayMetrics").newInstance();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
w = metrics.widthPixels * 25.4 / metrics.xdpi;
y = metrics.heightPixels * 25.4 / metrics.ydpi;

假设手势是在横屏模式下记录的,当以横屏模式回放时,手势过大,并且过于偏向左下角。然后使用Object GestureBuilder.scale(scaleX, scaleY, originX, originY)Object GestureBuilder.translate(x, y)进行平移到右上角,这是一个可能的解决方案。

"The effect of a rotation, scale and translate transformation"

例如,将手势大小缩小为3/4,并向右移动5厘米,向上移动1厘米。

gesture(waitForObject(":some_object"), readGesture("Gesture_1").scale(0.75).translate(50,-10));

当使用squishide时,在脚本中断点使用控制台视图进行手势变换实验。

另一种方法可能是仅将手势缩放到右上角原点。

var gst = readGesture("Gesture_1");
gesture(waitForObject(":some_object"), gst.scale(0.75, 0.75, gst.areaWidth, 0));

在某些情况下,可能需要动态创建手势,例如,为了更精确的控制或基于运行时状态信息。此时可以使用Gesture creation方法。

以下是一个投掷手势的示例,即在800x1200像素屏幕上,两指以两秒钟内逆时针曲线运动。

var tb = new GestureBuilder(800, 1280, GestureBuilder.Pixel);
tb.addStroke( 600, 400 );
tb.curveTo(1000, 500, 300, 300, 300, 200, 400 );
tb.addStroke( 200, 800 );
tb.curveTo(1000, 300, 900, 500, 900, 600, 800);
tb.build();
gesture(waitForObject(":some_object"), tb);

以下是一个缩放手势的示例,即两指互相远离,同样在1秒内完成。这次被写为一个语句。

gesture(waitForObject(":some_object"),
        new GestureBuilder(800, 1280, GestureBuilder.Pixel)
           .addStroke( 500, 400 )
           .lineTo(1000, 700, 100 )
           .addStroke( 300, 700 )
           .lineTo(1000, 100, 1000)
           .build());

在上面的两个示例中,坐标值基于800x1280的区域大小。对于不同的屏幕尺寸或手势应该回放的小部件尺寸和位置不同的尺寸,需要一些计算来获取这些值。以下策略可能在处理这些时有助于降低复杂度。

  1. 根据屏幕尺寸,在x轴[-0.5,0.5]和y轴[-0.5,0.5]的范围内以及1秒的持续时间内创建一个手势。
  2. 将其平移到目标小部件的中心。
  3. 按照小部件最大尺寸对其进行缩放,以这个小部件的中心作为原点。
  4. 调整持续时间。

"S-shape"

以下是一个例子,这是一个S形图形

var activity = findObject(":Your_Activity").nativeObject;
var metrics = activity.getClass().forName("android.util.DisplayMetrics").newInstance();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

var tb = new GestureBuilder(metrics.widthPixels, metrics.heightPixels, GestureBuilder.Pixel)
             .addStroke(0, 0.5)
             .curveTo(500, -0.5, 0.5, -0.5, 0, 0, 0)
             .curveTo(500, 0.5, 0, 0.5, -0.5, 0, -0.5)
             .build();

var widget = findObject(":Some widget");
var scale = widget.width > widget.height ? widget.height : widget.width;
var centerX = widget.screenX + widget.width/2;
var centerY = widget.screenY + widget.height/2;
gesture(widget,
        tb.translate(centerX, centerY)
          .scale(scale, -scale, centerX, centerY)
          .accelerate(1/2))

此示例将图形定义为以正y轴向上。为确保图形不会翻转,需要在x轴上使用镜像。技巧是在垂直方向使用负缩放因子。

将定义的手势保持在大于-0.5到0.5的范围内具有优点,因为总大小为1。因此,可以在小部件大小内进行缩放,而不会被缩放到屏幕边界之外。将(0, 0)放置在中心简化了平移,只需将其平移到小部件的中心。

©2024 Qt公司有限公司。此处包含的文档贡献是各自所有者的版权。
此处提供的文档根据自由软件基金会发布的GNU自由文档许可协议的条款进行许可,版本为1.3。
Qt及其相关标志是芬兰和/或其他国家全球Qt公司有限责任公司的商标。所有其他商标均为各自所有者的财产。