Appium Python Client

在上篇Appium+iOS+Mac 环境搭建的基础上,复制翻译了Appium Python Client以作为后续的使用手册。

Appium Python客户端完全符合Selenium 3.0规范草案,其中一些帮助者可以更轻松地在Python中进行移动测试。 大多数用法仍然与Selenium 2(WebDriver)一样,并且随着官方Selenium Python bindings开始实现将在下面使用实现的新规范,因此可以编写可用于两种绑定的测试代码。

要立即使用新功能,并使用函数的超集,而不是在测试代码中包含Selenium webdriver模块,请改用Appium中的模块。

from appium import webdriver

从那里你的大部分测试代码将无需任何改变。

作为以下代码示例的基础,以下设置UnitTest环境:

# Android environment
import unittest
from appium import webdriver

desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '8.1'
desired_caps['automationName'] = 'uiautomator2'
desired_caps['deviceName'] = 'Android Emulator'
desired_caps['app'] = PATH('../../../apps/selendroid-test-app.apk')

self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
import unittest
from appium import webdriver

desired_caps = {}
desired_caps['platformName'] = 'iOS'
desired_caps['platformVersion'] = '11.4'
desired_caps['automationName'] = 'xcuitest'
desired_caps['deviceName'] = 'iPhone Simulator'
desired_caps['app'] = PATH('../../apps/UICatalog.app.zip')

self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

更改或添加功能

  • 在原生和Webview之间切换

对于移动测试,之前用于在窗口之间切换的Selenium方法被用于在本机应用程序和webview上下文之间切换。 为此明确的方法已添加到Selenium 3规范中,因此将使用这些“上下文”方法。

要获取当前上下文,而不是调用driver.current_window_handle

current = driver.current_context

使用driver.window_handles不会检索可用的上下文

driver.contexts

最后,要切换到新的上下文而不是driver.switch_to.window(name),请使用可比较的上下文方法

context_name = "WEBVIEW_1"
driver.switch_to.context(context_name)

通过iOS UIAutomation搜索查找元素

这允许使用UIAutomation库使用递归元素搜索找到iOS应用程序中的元素。 仍然支持UIAutomation的iOS设备支持此方法,即早于XCUITEST的版本.

添加方法driver.find_element_by_ios_uiautomation和driver.find_elements_by_ios_uiautomation。

el = self.driver.find_element_by_ios_uiautomation('.elements()[0]')
self.assertEqual('UICatalog', el.get_attribute('name'))
els = self.driver.find_elements_by_ios_uiautomation('.elements()')
self.assertIsInstance(els, list)

Finding elements by Android UIAutomator search

这允许使用UIAutomator库使用递归元素搜索找到Android应用程序中的元素。 添加方法driver.find_element_by_android_uiautomator和driver.find_elements_by_android_uiautomator。

el = self.driver.find_element_by_android_uiautomator('new UiSelector().description("Animation")')
self.assertIsNotNone(el)
els = self.driver.find_elements_by_android_uiautomator('new UiSelector().clickable(true)')
self.assertIsInstance(els, list)

通过Android视图标签搜索查找元素

此方法允许使用View#标记查找元素。 此方法适用于Espresso驱动程序。

添加方法driver.find_element_by_android_viewtag和driver.find_elements_by_android_viewtag。

el = self.driver.find_element_by_android_viewtag('a tag name')
self.assertIsNotNone(el)
els = self.driver.find_elements_by_android_viewtag('a tag name')
self.assertIsInstance(els, list)

通过iOS谓词查找元素

此方法允许使用iOS谓词查找元素。 这些方法采用谓词格式的字符串,包括元素类型和字段值。

添加方法driver.find_element_by_ios_predicate和find_elements_by_ios_predicate。

el = self.driver.find_element_by_ios_predicate('wdName == "Buttons"')
self.assertIsNotNone(el)
els = self.driver.find_elements_by_ios_predicate('wdValue == "SearchBar" AND isWDDivisible == 1')
self.assertIsInstance(els, list)

Finding elements by iOS class chain

此方法仅适用于XCUITest驱动程序

此方法允许使用iOS类链查找元素。 这些方法采用类链的格式的字符串,包括元素类型。

添加方法driver.find_element_by_ios_class_chain和find_elements_by_ios_class_chain。

el = self.driver.find_element_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton[3]')
self.assertIsNotNone(el)
els = self.driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton')
self.assertIsInstance(els, list)

Finding elements by Accessibility ID

允许使用“辅助功能ID”找到元素。 这些方法采用表示附加到给定元素的可访问性标识或标签的字符串,例如,对于iOS,可访问性标识符,对于Android,采用内容描述。 添加方法driver.find_element_by_accessibility_id和find_elements_by_accessibility_id。

el = self.driver.find_element_by_accessibility_id('Animation')
self.assertIsNotNone(el)
els = self.driver.find_elements_by_accessibility_id('Animation')
self.assertIsInstance(els, list)

触摸动作

为了适应移动触摸动作以及涉及多个指针的触摸动作,Selenium 3.0草案指定了“触摸手势”和“多动作”,它们构建在触摸动作之上。

move_to:请注意,如果没有元素,请使用关键字参数

API围绕TouchAction对象构建,TouchAction对象是要按顺序执行的一个或多个动作的链。 行动是:

  • perform

perform方法将链发送到服务器以便生效。 它还清空了动作链,因此可以重用该对象。 它将在所有单一动作链的末尾,但在编写多动作链时未被使用。

  • tap

tap方法独立,无法与其他方法链接。 如果您需要类似水龙头的动作来启动更长的链条,请使用按下。

它可以是带有可选x-y偏移的元素,也可以是tap的绝对x-y坐标,以及可选的计数。

el = self.driver.find_element_by_accessibility_id('Animation')
action = TouchAction(self.driver)
action.tap(el).perform()
el = self.driver.find_element_by_accessibility_id('Bouncing Balls')
self.assertIsNotNone(el)
  • press
  • long_press
  • release
  • move_to
  • wait
  • cancel

多点触控动作

除了在单个手势内执行的动作链之外,还可以同时执行多个链,以模拟多手指动作。 这是通过构建一个MultiAction对象来完成的,该对象包含许多单独的TouchAction对象,每个“手指”对应一个。

给定两个彼此相邻的列表,我们可以独立滚动它们,但同时:

els = self.driver.find_elements_by_class_name('listView')
a1 = TouchAction()
a1.press(els[0]) \
    .move_to(x=10, y=0).move_to(x=10, y=-75).move_to(x=10, y=-600).release()

a2 = TouchAction()
a2.press(els[1]) \
    .move_to(x=10, y=10).move_to(x=10, y=-300).move_to(x=10, y=-600).release()

ma = MultiAction(self.driver, els[0])
ma.add(a1, a2)
ma.perform();

特定于Appium的触摸动作

移动测试人员需要做很少的操作,使用Touch和Multi-touch Action API进行构建可能相对复杂。 为此,我们在Appium客户端中提供了一些便捷方法。

  • driver.tap

在WebDriver对象上,此方法允许使用多个手指轻敲,只需传入x-y坐标数组即可。

el = self.driver.find_element_by_name('Touch Paint')
action.tap(el).perform()

# set up array of two coordinates
positions = []
positions.append((100, 200))
positions.append((100, 400))

self.driver.tap(positions)
  • driver.swipe

从一个点滑动到另一个点。

  • driver.zoom

放大元素,进行捏合操作。

  • driver.pinch

缩小元素,进行操作捏合。

应用管理方法

在测试中,有时您希望管理正在运行的应用程序,例如安装或删除应用程序等。

背景应用程序

方法driver.background_app将正在运行的应用程序发送到后台指定的时间(以秒为单位)。 在此之后,应用程序将返回到前台。

driver.background_app(1)
sleep(2)
el = driver.find_element_by_name('Animation')
assertIsNotNone(el)

检查是否安装了应用程序

要检查设备上当前是否安装了应用程序,请使用device.is_app_installed方法。 此方法获取应用程序的bundle id并返回True或False。

assertFalse(self.driver.is_app_installed('sdfsdf'))
assertTrue(self.driver.is_app_installed('com.example.android.apis'))

安装应用程序

要在设备上安装卸载的应用程序,请使用device.install_app,发送应用程序文件或存档的路径。

assertFalse(driver.is_app_installed('io.selendroid.testapp'))
driver.install_app('/Users/isaac/code/python-client/test/apps/selendroid-test-app.apk')
assertTrue(driver.is_app_installed('io.selendroid.testapp'))

删除应用程序

如果需要从设备中删除应用程序,请使用device.remove_app,传入应用程序ID。

assertTrue(driver.is_app_installed('com.example.android.apis'))
driver.remove_app('com.example.android.apis')
assertFalse(driver.is_app_installed('com.example.android.apis'))

关闭并启动应用程序

要启动所需功能中指定的应用程序,请调用driver.launch_app。 关闭该应用程序由driver.close_app启动

assertIsNotNone(el)
driver.close_app();

try:
    driver.find_element_by_name('Animation')
except Exception as e:
    pass # should not exist

driver.launch_app()
el = driver.find_element_by_name('Animation')
assertIsNotNone(el)

重置应用程序

要重置正在运行的应用程序,请使用driver.reset。

el = driver.find_element_by_name('App')
el.click()

driver.reset()
sleep(5)

el = driver.find_element_by_name('App')
assertIsNotNone(el)

其他方法

开始任意活动
driver.start_activity方法打开设备上的任意活动。 如果活动不是被测试应用程序的一部分,它还将启动活动的应用程序。

driver.start_activity('com.foo.app', '.MyActivity')

检索应用程序字符串

属性方法driver.app_strings从设备上的应用程序返回应用程序字符串。

strings = driver.app_strings

将关键事件发送到Android设备

driver.keyevent方法将密钥代码发送到设备。 密钥代码可以在这里找到。 仅适用于Android。

# sending 'Home' key event
driver.press_keycode(3)

在iOS中隐藏键盘

要在iOS中隐藏键盘,请使用driver.hide_keyboard。 如果发送了密钥名称,则将按下具有该名称的键盘密钥。 如果没有传入参数,则通过点击文本字段外的屏幕来隐藏键盘,从而从中移除焦点。

# get focus on text field, so keyboard comes up
el = driver.find_element_by_class_name('android.widget.TextView')
el.set_value('Testing')

el = driver.find_element_by_class_name('keyboard')
assertTrue(el.is_displayed())

driver.hide_keyboard('Done')

assertFalse(el.is_displayed())
# get focus on text field, so keyboard comes up
el = driver.find_element_by_class_name('android.widget.TextView')
el.set_value('Testing')

el = driver.find_element_by__name('keyboard')
assertTrue(el.is_displayed())

driver.hide_keyboard()

assertFalse(el.is_displayed())

检索当前正在运行的包和活动

属性方法driver.current_package返回设备上运行的当前包的名称。

package = driver.current_package
assertEquals('com.example.android.apis', package)

属性方法driver.current_activity返回设备上运行的当前活动的名称。

activity = driver.current_activity
assertEquals('.ApiDemos', activity)

直接在元素上设置值

有时需要直接在设备上设置元素的值。 为此,调用方法driver.set_value或element.set_value。

el = driver.find_element_by_class_name('android.widget.EditText')
driver.set_value(el, 'Testing')

text = el.get_attribute('text')
assertEqual('Testing', text)

el.set_value('More testing')
text = el.get_attribute('text')
assertEqual('More testing', text)

从设备中检索文件

要从设备检索文件的内容,请使用driver.pull_file,它返回在Base64中编码的指定文件的内容。

# pulling the strings file for our application
data = driver.pull_file('data/local/tmp/strings.json')
strings = json.loads(data.decode('base64', 'strict'))
assertEqual('You can\'t wipe my data, you are a monkey!', strings[u'monkey_wipe_data'])

将文件放在设备上

要将文件放在特定位置的设备上,请使用driver.push_file方法,该方法将路径和编码为Base64的数据写入文件。

path = 'data/local/tmp/test_push_file.txt'
data = 'This is the contents of the file to push to the device.'
driver.push_file(path, data.encode('base64'))
data_ret = driver.pull_file('data/local/tmp/test_push_file.txt').decode('base64')
self.assertEqual(data, data_ret)

结束测试覆盖率

Android模拟器中有一些功能可用于检测某些活动。 有关此信息,请参阅Appium文档。 要结束此覆盖并检索数据,请使用driver.end_test_coverage,传入正在进行工具化的intent,以及设备上的coverage.ec文件的路径。

coverage_ec_file = driver.end_test_coverage(intent='android.intent.action.MAIN', path='')

锁定设备

要在iOS上锁定设备一段时间,请使用driver.lock。 参数是解锁前等待的秒数。

摇晃设备

要摇动设备,请使用driver.shake。

Appium设置

设置是appium引入的新概念。 它们目前不是Mobile JSON Wire Protocol或Webdriver规范的一部分。

设置是指定appium服务器行为的一种方法。

设置是:

可变,它们可以在会话期间更改仅在会话期间相关它们被应用。 它们会针对每个新会话重置。 控制appium服务器在测试自动化期间的行为方式。 它们不适用于控制受测试的应用程序或设备。

有关更多信息,请参阅文档。

要获得设置:

settings = driver.get_settings()

要设置:

driver.update_settings({"some setting": "the value"})

你可能感兴趣的:(Appium Python Client)