移动端测试之appium滑动操作详解

appium滑动操作详解

不管是在appium还是selenium的滑动操作都是如出一辙的,都是基于web driver中提供的TouchAction完成的。这里说一些关于web滑动的题外话,web自动化测试最好用的方法还是使用js,可以通过执行js脚本的方式达到向下滑动加载更多页面的目的。

TouchAction目前版本已经不再被支持了,取而代之的是ActionChains,ActionChains是一种自动化底层互动的方式,如鼠标移动、鼠标按键动作、按键和上下文菜单的交互。这对做更复杂的动作很有用,如悬停和拖放。生成用户动作。当你在ActionChains对象上调用动作的方法时、动作会被存储在ActionChains对象的队列中。当你调用perform()时,事件会按照它们的顺序被触发、被排队的顺序触发。

ActionChains可以连锁模式使用:

menu = driver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = driver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
​
ActionChains(driver).move_to_element(menu).click(hidden_submenu).former()

或者可以将动作逐一排队,然后执行:

menu = driver.find_element(By.CSS_SELECTOR, ".nav")
hidden_submenu = driver.find_element(By.CSS_SELECTOR, ".nav #submenu1")
​
actions = ActionChains(driver)
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()

无论哪种方式,动作都是按照它们被调用的顺序执行的,一个接一个的被执行。ActionChains中包含了多种模拟操作,包括但不限于按键操作、拖拽操作、单击、双击、移动等操作。使用的时候要 from selenium.webdriver import ActionChains。

appium贴心的帮我们封装了ActionChains中的一些方法,根据坐标进行滑动的方法有self.driver.swipe(start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0),其实本质就是封装了ActionChains的move to 操作,

actions = ActionChains(self)
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.pause(duration / 1000)
actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)
actions.w3c_actions.pointer_action.release()
actions.perform()
return self  # type: ignore

如果你觉得这种传值方式你不满意,不想要每次都用location函数计算element坐标再去滑动的话,知道原理后也可以自己封装一个方法使用,将获取元素location的方法写在里面,改造成这样:

def swipe_one_button_to_another_button(self, start_element, end_element):
    action = TouchAction(self.driver)
    start_location = start_element.location
    start_x = start_location['x']
    start_y = start_location['y']
    end_location = end_element.location
    end_x = end_location['x']
    end_y = end_location['y']
    action.press(x=start_x, y=start_y).move_to(x=end_x, y=end_y).release().perform()

这样就可以实现传入element了,如果你想传locator那也可以将find element的逻辑写在函数中。

self.driver.drag_and_drop(start_element, end_element), 这个方法更像是上面改造了的传值方法,但是观察源码会发现有一点区别:

def drag_and_drop(self, origin_el: WebElement, destination_el: WebElement) -> 'WebDriver':
    """Drag the origin element to the destination element
​
    Args:
        origin_el: the element to drag
        destination_el: the element to drag to
​
    Returns:
        Union['WebDriver', 'ActionHelpers']: Self instance
    """
    actions = ActionChains(self)
    # 'mouse' pointer action
    actions.w3c_actions.pointer_action.click_and_hold(origin_el)
    actions.w3c_actions.pointer_action.move_to(destination_el)
    actions.w3c_actions.pointer_action.release()
    actions.perform()
    return self  # type: ignore

这里有一步click and hold的操作,所以self.driver.drag_and_drop是点击第一个按钮然后拖拽到下一个按钮,页面往往不会停在最后的按钮上,而是惯性再向上一段距离。

在日常使用中可以根据自己的从需求完成不同方法的封装,一般情况下我们可能会遇到

  1. 从element拖到另一个element,这时候可以使用self.driver.drag_and_drop

  2. 从一个坐标到另一个坐标,这时候可以使用self.driver.swipe

  3. 从当前位置到另一个element,可以自己封装一个方法

def swipe_from_current_to_button(self, target_element):
    action = TouchAction(self.driver)
    action.move_to(target_element).release().perform()
  1. 任意向上或者向下滑动一段距离

def swipe_random_up_distance(self):
    action = TouchAction(self.driver)
    screen_size = self.driver.get_window_size()
    screen_width = screen_size['width']
    screen_height = screen_size['height']
    start_x = screen_width // 2
    start_y = screen_height // 2
    end_x = start_x
    end_y = start_y - 200 # 或者 +200
    action.press(x=start_x, y=start_y).move_to(x=end_x, y=end_y).release().perform()
  1. 滑动屏幕直到有某个element,这个方法很常用,因为随着页面的render会出现我们想要的按钮,而不会一次render所有按钮

def swipe_screen_until_to_element(self, locator):
    while True:
        try:
            self.driver.find_element(*locator)
            break
        except NoSuchElementException:
            self.swipe_random_down_distance()

当然Android中有个神奇的方法也可以完成一样的事情,这是源于Android底层给我们抛出的方法

self.driver.find_element_by_android_uiautomator(
    'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("目标按钮文本").instance(0));'
).click()

这里会自动向上或者向下滚动查找目标按钮,new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView这个方法是根据UIautomator的方法完成的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值