monkeyrunner 中的动作不可靠
Actions in monkeyrunner are not reliable
问题
我的应用程序有一个类似地图的 canvas 用户可以通过拖动地图来移动它。我想要完成的是将地图移动到 100px 的右侧,然后移动到 100px 的左侧,并检查中心位置是否相同。
代码如下:
device.drag((640, 360), (640 - 100, 360))
device.drag((640, 360), (640 + 100, 360))
# check
这并不能每次都可靠地将地图带到同一个地方。有时设备会挂起或变慢并且移动的像素很少;有时在最后一步中它走得更快,给了它动力。
有什么办法可以精确拖动屏幕一定的像素数?设备挂了或者慢了也没关系,只要最后的动作正确就行。
我的尝试
我尝试调整第三个 (duration
) 和第四个 (steps
) 参数,但无济于事。
我还尝试通过以下方式实现我的自定义拖动代码:
# Touch down screen
device.touch(100, 500, MonkeyDevice.DOWN)
# Move from 100, 500 to 200, 500
for i in range(1, 11):
device.touch(100 + 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(200, 500, MonkeyDevice.UP)
然后到另一边:
# Touch down screen
device.touch(200, 500, MonkeyDevice.DOWN)
# Move from 200, 500 to 100, 500
for i in range(1, 11):
device.touch(200 - 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(100, 500, MonkeyDevice.UP)
以类似的方式,我也尝试使用以下方法测试我的游戏手柄按键:
for _ in range(0, 10):
device.press('KEYCODE_DPAD_RIGHT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
for _ in range(0, 10):
device.press('KEYCODE_DPAD_LEFT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
甚至有时 monkeyrunner
会跳过事件或不考虑向上事件,因此导致长按(相当于“在地图上继续移动”)。
有用的参考资料:
drag
touch
MonkeyDevice.MOVE
patch
MonkeyDevice.MOVE
sample code
MonkeyDevice.MOVE
exists!
很好的问题。
看完之后我也很好奇,我想知道这个问题是否也影响了AndroidViewClient/culebra(哪个更可靠)。
但是,正如以下步骤所表明的那样,它可能与地图移动的方式有关,而不是与发送事件的不同协议的可靠性有关。此外,还给出了一种自动化测试的方法,正如您提到的,您正在对结果进行视觉比较。
我认为分享这个会很有帮助,它可能会给你更多的想法来测试你的应用程序。
开始使用 culebra GUI 创建测试。
然后我稍微编辑了测试以分解点并添加相反的阻力。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2016 Diego Torres Milano
Created on 2017-03-04 by Culebra
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
import pkg_resources
pkg_resources.require('androidviewclient>=13.0.0')
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper, UiScrollable, UiObject, UiObject2
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': False, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': None, 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': False, 'find-views-with-text': True, 'prepend-to-sys-path': False, 'install-apk': None, 'drop-shadow': False, 'output': None, 'unit-test-method': None, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
d = '/tmp/'
p = (377.14, 380.86)
q = (175.14, 380.86)
self.vc.writeImageToFile(d + 'map-start.png')
# Each step execution is throttled to 5ms per step
# So for a 400 steps, the swipe will take about 2 second to complete
steps = 400
duration = 2000
# Let's give some extra delay.
sleep = 3
for n in range(10):
print n
self.device.dragDip(p, q, duration, steps)
self.vc.sleep(sleep)
self.device.dragDip(q, p, duration, steps)
self.vc.sleep(sleep)
self.vc.writeImageToFile(d + 'map-finish.png')
self.device.compare(d + 'map-finish.png', d + 'map-start.png', d + 'map-compare.png')
if __name__ == '__main__':
CulebraTests.main()
一旦运行,这些是迭代前后的结果
在最后一张图片中,您可以看到视觉比较,它显示出轻微的移动。不过,我认为这可能正是 Google 地图的做法。
我还使用了 CulebraTester,它使用基于 UiAutomator 的完全不同的后端,但出现了同样的问题。所以我认为与 drag
.
无关
我用 appetizer-toolkit 测量了视觉差异并发现了类似的问题。只是一些想法和以前的经验。
为了计时,我们尝试了几种后端,例如sendevent
、MonkeyDevice
/Chimp
。正如我提到的,sendevent
会为每个点创建一个进程,这完全会浪费时间。MonkeyDevice
设备上的代理并不像它应该的那样可靠,我们进行了一些初步尝试,但后来放弃了。如果您有兴趣,请检查 this。当前可接受的后端是 openstf/minitouch
,它与当前的工具包一起使用。在校准和一些调整之后,我相信该工具包会变得更好(目前针对 1.0.5
发布)
我怀疑使用任何那些输入记录和重放工具都无法实现实际的 "deterministic replays"。根据我们的经验,即使我们可以对输入事件(x、y 和时间)实施完美的确定性,该应用程序仍然会有其他非确定性,特别是滞后、网络活动和 Canvas 视图响应。我怀疑您遇到的问题是 MonkeyDevice 的不精确性和 Canvas 视图问题的叠加。因此,对于您的更高层次的设计,请将这些工具以及我们的工具包视为 "input automation tool" 并对错误有一定的容忍度。
问题
我的应用程序有一个类似地图的 canvas 用户可以通过拖动地图来移动它。我想要完成的是将地图移动到 100px 的右侧,然后移动到 100px 的左侧,并检查中心位置是否相同。
代码如下:
device.drag((640, 360), (640 - 100, 360))
device.drag((640, 360), (640 + 100, 360))
# check
这并不能每次都可靠地将地图带到同一个地方。有时设备会挂起或变慢并且移动的像素很少;有时在最后一步中它走得更快,给了它动力。
有什么办法可以精确拖动屏幕一定的像素数?设备挂了或者慢了也没关系,只要最后的动作正确就行。
我的尝试
我尝试调整第三个 (duration
) 和第四个 (steps
) 参数,但无济于事。
我还尝试通过以下方式实现我的自定义拖动代码:
# Touch down screen
device.touch(100, 500, MonkeyDevice.DOWN)
# Move from 100, 500 to 200, 500
for i in range(1, 11):
device.touch(100 + 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(200, 500, MonkeyDevice.UP)
然后到另一边:
# Touch down screen
device.touch(200, 500, MonkeyDevice.DOWN)
# Move from 200, 500 to 100, 500
for i in range(1, 11):
device.touch(200 - 10 * i, 500, MonkeyDevice.MOVE)
time.sleep(0.1)
# Extra sleep to avoid momentum
time.sleep(0.2)
# Remove finger from screen
device.touch(100, 500, MonkeyDevice.UP)
以类似的方式,我也尝试使用以下方法测试我的游戏手柄按键:
for _ in range(0, 10):
device.press('KEYCODE_DPAD_RIGHT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
for _ in range(0, 10):
device.press('KEYCODE_DPAD_LEFT', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.1)
甚至有时 monkeyrunner
会跳过事件或不考虑向上事件,因此导致长按(相当于“在地图上继续移动”)。
有用的参考资料:
drag
touch
MonkeyDevice.MOVE
patchMonkeyDevice.MOVE
sample codeMonkeyDevice.MOVE
exists!
很好的问题。 看完之后我也很好奇,我想知道这个问题是否也影响了AndroidViewClient/culebra(哪个更可靠)。
但是,正如以下步骤所表明的那样,它可能与地图移动的方式有关,而不是与发送事件的不同协议的可靠性有关。此外,还给出了一种自动化测试的方法,正如您提到的,您正在对结果进行视觉比较。
我认为分享这个会很有帮助,它可能会给你更多的想法来测试你的应用程序。
开始使用 culebra GUI 创建测试。
然后我稍微编辑了测试以分解点并添加相反的阻力。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2016 Diego Torres Milano
Created on 2017-03-04 by Culebra
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
import pkg_resources
pkg_resources.require('androidviewclient>=13.0.0')
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper, UiScrollable, UiObject, UiObject2
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': False, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': None, 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': False, 'find-views-with-text': True, 'prepend-to-sys-path': False, 'install-apk': None, 'drop-shadow': False, 'output': None, 'unit-test-method': None, 'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def testSomething(self):
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
d = '/tmp/'
p = (377.14, 380.86)
q = (175.14, 380.86)
self.vc.writeImageToFile(d + 'map-start.png')
# Each step execution is throttled to 5ms per step
# So for a 400 steps, the swipe will take about 2 second to complete
steps = 400
duration = 2000
# Let's give some extra delay.
sleep = 3
for n in range(10):
print n
self.device.dragDip(p, q, duration, steps)
self.vc.sleep(sleep)
self.device.dragDip(q, p, duration, steps)
self.vc.sleep(sleep)
self.vc.writeImageToFile(d + 'map-finish.png')
self.device.compare(d + 'map-finish.png', d + 'map-start.png', d + 'map-compare.png')
if __name__ == '__main__':
CulebraTests.main()
一旦运行,这些是迭代前后的结果
在最后一张图片中,您可以看到视觉比较,它显示出轻微的移动。不过,我认为这可能正是 Google 地图的做法。
我还使用了 CulebraTester,它使用基于 UiAutomator 的完全不同的后端,但出现了同样的问题。所以我认为与 drag
.
我用 appetizer-toolkit 测量了视觉差异并发现了类似的问题。只是一些想法和以前的经验。
为了计时,我们尝试了几种后端,例如sendevent
、MonkeyDevice
/Chimp
。正如我提到的,sendevent
会为每个点创建一个进程,这完全会浪费时间。MonkeyDevice
设备上的代理并不像它应该的那样可靠,我们进行了一些初步尝试,但后来放弃了。如果您有兴趣,请检查 this。当前可接受的后端是 openstf/minitouch
,它与当前的工具包一起使用。在校准和一些调整之后,我相信该工具包会变得更好(目前针对 1.0.5
发布)
我怀疑使用任何那些输入记录和重放工具都无法实现实际的 "deterministic replays"。根据我们的经验,即使我们可以对输入事件(x、y 和时间)实施完美的确定性,该应用程序仍然会有其他非确定性,特别是滞后、网络活动和 Canvas 视图响应。我怀疑您遇到的问题是 MonkeyDevice 的不精确性和 Canvas 视图问题的叠加。因此,对于您的更高层次的设计,请将这些工具以及我们的工具包视为 "input automation tool" 并对错误有一定的容忍度。