Appium Android 自动化实践:Appium+Python 入门

于归 · 2017年09月09日 · 最后由 百事可乐 回复于 2018年11月08日 · 5172 次阅读

写在开头

在社区潜水一年多,潜水期间社区里的内容解决了我在工作中大大小小的各种问题,正好这段时间开始又重新开始研究了移动端自动化测试,就准备把自己瞎琢磨的一些东西分享给有需要的朋友吧~ 😂

环境搭建

appium 的环境搭建社区里已经有 hin 多 hin 详细的帖子了,可以参照这篇帖子:Appium macOS 下的 Appium 安装与配置
,这里就不多加介绍了,还没有搭建环境的或者搭建过程中碰到一些问题的,可以尝试看看这篇帖子,说不定有你想要的答案哦~😄

正文内容

Android 元素定位

下面开始介绍目前所了解到的两种元素定位的工具吧~

uiautomatorviewer

uiautomatorviewer 是 Android SDK 自带的工具,mac 是在../../Library/Android/sdk/tools/bin
路径下,在目录下执行命令./uiautomatorviewer就可以愉快的用它进行元素定位了~相信大家用的都比较多的啦~😇
下面使用的是我厂的产品(不打广告),如下:

😂 想知道哪里点哪里,真的是 so easy~
不过用的时候碰到这个问题:

😂 我把模拟器重启了一下就好了,尴尬~

Appium Desktop

Appium Desktop 是在 appium 官方网站下载的,刚用的时候还有点懵逼,这特么是个什么鬼~
😂 后来通过查找各种资料,终于会用了,可以出来显摆一下了~
入口如下图,开启 appium 服务之后,点击上面的「Start New Session」按钮,就进入到图右边的界面啦~

然后像右图一样配置好测试设备的信息,点击开始就可以进入到获取元素定位的界面,如下图:

😀 这块功能挺好玩的,中间部分有个小眼睛的按钮,点击可以进行录制,还能把操作转成你想要的测试代码,右边还有三个操作「Tap」、「send keys」和「clear」

测试脚本编写

导入相关的库

import unittest # 单元测试框架
from appium import webdriver # appium库

用 unittest 编写测试脚本框架

class AppTest(unittest.TestCase):

    def setUp(self):
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '5.1'
        desired_caps['deviceName'] = 'Android Emulator'
        desired_caps['app'] = '/Users/yugui/Desktop/idxyer-v7.3.3.apk'
        desired_caps['noReset'] = False
        desired_caps["unicodeKeyboard"] = "True"
        desired_caps["resetKeyboard"] = "True"

        self.wd = webdriver.Remote('http://127.0.0.1:4725/wd/hub', desired_caps)
        self.wd.implicitly_wait(60)

    def test_login(self):
        pass

    def tearDown(self):
        self.wd.quit()

if __name__ == '__main__':
    unittest.main()

编写测试用例

还是以我厂的 app 为例,想写一个登录的小 demo,但是实践过程中发现以下几个问题:

  1. 大多数新装的 app 都会出现几页的欢迎页,那么问题来了:
    1. 欢迎页的上下左右滑动
    2. 如果不是新装的 app,那么就应该是直接登录就可以了,就不用滑动欢迎页了
  2. 用户登录状态
    1. 如果用户未登录,那么才能输入用户名密码进行登录
    2. 如果用户已登录,直接返回用户已登录的信息,进行其他的操作就可以了

接下来就开始解决这些问题啦~👏

  1. 滑动页面元素,可以使用 swipe 来进行操作,我在这里封装了一个方法,以方便使用,下面贴代码:
def SwipeLeft(self, duration):
    # 获取手机分辨率的宽度
    x = self.wd.get_window_size()['width']
    # 获取手机分辨率的高度
    y = self.wd.get_window_size()['height']
    self.wd.swipe(x * 9/10, y/2, x/10, y/2, duration)
  1. 当打开 app 时,没有欢迎页,那么就不需要进行滑动页面了,所以我们应该在这里判断元素是否存在,如果存在则滑动页面,不存在则输出相应信息并进行下一步操作 在这里我也是封装了一个函数,因为感觉有好些地方都要用到呢~ 下面贴代码:
def findElement(self, element):
    try:
        WebDriverWait(self.wd, 10).until(expected_conditions.presence_of_element_located((By.ID, element)))
        return True
    except selenium.common.exceptions.TimeoutException:
        return False
    except selenium.common.exceptions.NoSuchElementException:
        return False

🙃 因为元素找不到有多重原因,有可能是超时也有可能是没有这个元素,所以这里做了两个异常处理。

下面是正经的测试代码,

def test_login(self):
    if self.findElement('cn.dxy.idxyer:id/start_up_welcome_image_iv'):
        for i in range(3):
            self.SwipeLeft(1000)
        self.wd.find_element_by_id('cn.dxy.idxyer:id/start_up_welcome_enter_tv').click()
    else:
        print('欢迎页不存在的')
    self.wd.implicitly_wait(60)
    self.wd.find_element_by_id('cn.dxy.idxyer:id/main_mine_rb').click()
    if self.findElement('cn.dxy.idxyer:id/tab_account'):
        self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_username').set_value('111111111')
        self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_password').set_value('111111111')
        self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_login').click()
    else:
        print('用户已登录')

👊 到这里也差不多收工了,最后贴上完整的.py 文件:

import unittest
import selenium.common.exceptions
from appium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By


class AppTest(unittest.TestCase):

    def setUp(self):
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '5.1'
        desired_caps['deviceName'] = 'Android Emulator'
        desired_caps['app'] = '/Users/yugui/Desktop/idxyer-v7.3.3.apk'
        desired_caps['noReset'] = False
        desired_caps["unicodeKeyboard"] = "True"
        desired_caps["resetKeyboard"] = "True"

        self.wd = webdriver.Remote('http://127.0.0.1:4725/wd/hub', desired_caps)
        self.wd.implicitly_wait(60)

    # 向左滑动的函数
    def SwipeLeft(self, duration):
        x = self.wd.get_window_size()['width']
        y = self.wd.get_window_size()['height']
        self.wd.swipe(x * 9/10, y/2, x/10, y/2, duration)

    # 当元素找不到时
    def findElement(self, element):
        try:
            WebDriverWait(self.wd, 10).until(expected_conditions.presence_of_element_located((By.ID, element)))
            return True
        except selenium.common.exceptions.TimeoutException:
            return False
        except selenium.common.exceptions.NoSuchElementException:
            return False

    def test_login(self):
        if self.findElement('cn.dxy.idxyer:id/start_up_welcome_image_iv'):
            for i in range(3):
                self.SwipeLeft(1000)
            self.wd.find_element_by_id('cn.dxy.idxyer:id/start_up_welcome_enter_tv').click()
        else:
            print('欢迎页不存在的')
        self.wd.implicitly_wait(60)
        self.wd.find_element_by_id('cn.dxy.idxyer:id/main_mine_rb').click()
        if self.findElement('cn.dxy.idxyer:id/tab_account'):
            self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_username').set_value('1111111')
            self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_password').set_value('1111111')
            self.wd.find_element_by_id('cn.dxy.idxyer:id/sso_login').click()
        else:
            print('用户已登录')

    def tearDown(self):
        self.wd.quit()

if __name__ == '__main__':
    unittest.main()

最后

😳 第一次写分享,感觉篇幅有那么一丢丢长,能看到这里的应该都是真爱了,如果有不足的地方希望大家可以给出改进意见哪~

共收到 11 条回复 时间 点赞

赞一个!

正经的代码😂, 加油

kookooji 回复

😂 谢谢你的消灭零回复,哈哈

Scofell 回复

🙃 很正经的哦

案例很详细,入门必备

大神厉害了 支持😜 😜 😜

猜测是妹子,很萌

期待后续

羡慕 楼主框架用的这么熟练

我怎么不能执行第一个 if 语句呢,直接打印了

可以了,可能一开始改的东西,加多了

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 20:49
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册