18-20210511+15直播 appium 企业微信项目实战1+2

18-1 appium 企业微信项目实战1

APP 测试的时代背景

  • 按月发布->按周发布->按小时发布
  • 多端发布: Android、iOS、微信小程序、h5
  • 多环境发布: 联调环境、测试环境、预发布环境、线上环境
  • 多机型发布: 众多设备型号、众多系统版本
  • 多版本共存: 用户群体中存在多个不同的版本
  • 历史回归测试任务: 成百上千条业务用例如何回归

总结:加班 + 背锅

APPIUM 框架结构

在这里插入图片描述

APPIUM 引擎列表

PlatformDriverPlatform VersionsAppium VersionDriver Version
iOSXCUITest9.3+1.6.0+All
UIAutomation8.0 to 9.3AllAll
AndroidEspresso?+1.9.0+All
UiAutomator2?+1.6.0+All
UiAutomator4.3+AllAll
MacMac?+1.6.4+All
WindowsWindows10+1.6.0+All

APPIUM 环境安装

  • Android 环境配置

https://ceshiren.com/t/topic/2270

  • iOS 环境配置

https://ceshiren.com/t/topic/5530

  • 几点建议:

1、Appium Desktop版本不要太老1.15以上
2、Java 1.8
3、SDK build-tools/ 下对应的版本,需要使用<=29的版本
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

🔗木木官网-开发者必备说明书

木木官网-开发者必备说明书:
https://mumu.163.com/help/func/20190129/30131_797867.html

🔗ios环境搭建

ios环境搭建:ios环境搭建

🔗课程贴

课程贴:课程贴

🔗capability settings

Update settings:settings[settingsKey]

页面为动态刷新时,可设置capability特殊的settings参数,进行动态idel等待时间设置

  • 第一种方式:
    在这里插入图片描述
  • 第二种方式:
    在这里插入图片描述

获取 APP 的信息
app 入口,两种方式获取:

1、通过 logcat 日志获取

mac/Linux:  adb logcat ActivityManager:I | grep "cmp"
 
windows: adb logcat ActivityManager:I | findstr "cmp"后启动目标应用

2、通过 aapt 获取

mac/Linux: aapt dump badging wework.apk  | grep launchable-activity
 
Windows: aapt dump badging wework.apk  | findstr launchable-activity
  • 启动应用命令
adb shell am start -W -n <package-name>/<activity-name> -S

在这里插入图片描述

课堂练习

  • 企业微信打卡案例

前提条件
已登录状态( noReset=True)
打卡用例:
1、打开【企业微信】应用
2、进入【工作台】
3、点击【打卡】
4、选择【外出打卡】tab
5、点击【第N次打卡】
6、验证【外出打卡成功】
7、退出【企业微信】应用

参考代码

DesireCapability 配置

caps["noReset"] = "true"
caps['settings[waitForIdleTimeout]'] = 0   # 等待页面空闲的时间
 
caps['skipServerInstallation'] = ‘true'  # 跳过 uiautomator2 server的安装
caps['skipDeviceInitialization'] = ‘true'    # 跳过设备初始化
caps['dontStopAppOnReset'] = ‘true'    # 启动之前不停止app

滚动查找元素:

self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("添加成员").instance(0));')

课后作业

  • 使用 Appium 实现自动化添加联系人

18-2 appium 企业微信项目实战2

课程贴:https://ceshiren.com/t/topic/12237

一、常用的元素定位器

1)APP 元素定位

  • 测试步骤三要素
    • 定位、交互、断言
      • 断言:验证最后一步操作后结果的正确性
  • 定位
    • id 定位(优先级最高)
    • XPath 定位(速度慢,定位灵活)
    • Accessibility ID 定位(content-desc)1
    • Uiautomator 定位(仅 Android 速度快,语法复杂)
    • predicate 定位(仅 iOS )

2)XPATH 定位

xpath w3c

https://www.w3.org/TR/xpath-functions/

xpath : xml path的缩写,可以定位xml 文档中的一些标签

  • xpath表达式常用用法:

      1、逻辑运算符 (not、and 、or等) # 非、与、或
    
      2、表达式 (contains、ends_with、starts_with等)
    
  • 绝对定位: 不推荐
  • 相对定位:
//*	# 所有元素

//*[contains(@resource-id, ‘login’)]	# (❗️重点)包含,前面值包含后面值

//*[@text=‘登录’] 	# (❗️重点)text属性 = ‘登录’

//*[contains(@resource-id, ‘login’) and contains(@text, ‘登录’)] 	# (❗️重点)and 多层过滤,同时满足条件

//*[contains(@text, ‘登录’) or contains(@class, ‘EditText’)]	# (了解)获取元素列表find_elements

//*[ends-with(@text,'号') ] | //*[starts-with(@text,'姓名') ] 	# 两个定位的集合列表(了解) 类似于或,并集关系

//*[@clickable=“true"]//android.widget.TextView[string-length(@text)>0 and string-length(@text)<20]	# (了解) 获取text属性长度>0,且text属性长度<20

//*[contains(@text, ‘看点')]/ancestor::*//*[contains(@class, ‘EditText’)]	# (轴)(了解) 利用关键字ancestor(轴),先拿到元素所有的祖先节点元素“[contains(@text, ‘看点‘)”,再去过滤;效率较低,用的比较少

3)原生定位

  • Android 原生定位-Uiautomator
  • 写法:’new UiSelector().text(“text")’
  • iOS 原生定位-PredicateString

      例如:
    
      name == '测试'
    

在这里插入图片描述

4)TOAST 定位

appium使用uiautomator底层的机制来分析抓取toast,并且把toast放到控件树里面,但本身并不属于控件。

automationName:uiautomator2

使用xpath查找

//*[@class='android.widget.Toast']

//*[contains(@text, "xxxxx")]

5)企业微信实战 2

  • 企业微信 添加联系人 练习
  • 企业微信 添加多个联系人 练习
1、获取包+页面名字

在这里插入图片描述

抓取日志

在这里插入图片描述

获取当前页面名字(可获得主页名字),但不建议,建议以用户角度,从启动页进入
2、验证是否正确(shell命令启动程序)

在这里插入图片描述

3、代码
添加成员用例分析

在这里插入图片描述

工具

在这里插入图片描述
在这里插入图片描述

代码

faker造数据工具:
https://github.com/joke2k/faker

"""
__author__ = 'hogwarts_xixi'
__time__ = '2021/5/11 8:53 下午'
"""
# This sample code uses the Appium python client
# pip install Appium-Python-Client
# Then you can paste this into a file and simply run with Python
# pip install appium-python-client
from time import sleep

from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from faker import Faker
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait


class TestWX:
    def setup_class(self):
        self.fake = Faker('zh_CN')

    def setup(self):
        # 初始化
        caps = {}
        caps["platformName"] = "Android"
        # caps['skipDeviceInitialization'] = True
        # 包名+启动页名
        # mac/linux:adb logcat ActivityManager:I  | grep "cmp"
        # windows: adb logcat ActivityManager:I  | findstr "cmp"
        caps["appPackage"] = "com.tencent.wework"
        caps["appActivity"] = ".launch.LaunchSplashActivity"
        caps["deviceName"] = "hogwarts"
        caps["noReset"] = "True"
        caps["ensureWebviewsHavePages"] = True
        # 动态的设置caps 参数
        caps['settings[waitForIdleTimeout]'] = 0
        # 与server 建立连接,并且打开 caps 里面配置的页面LaunchSplashActivity
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
        # 隐式等待,在调用所有的find_element /find_elements方法的时候被激活
        self.driver.implicitly_wait(5)

    def teardown(self):
        # 资源消毁
        self.driver.quit()

    def test_demo(self):
        # 测试用例
        el1 = self.driver.find_element_by_xpath(
            "/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.LinearLayout/android.view.ViewGroup/android.widget.RelativeLayout[3]/android.widget.RelativeLayout/android.widget.TextView")

        el1.click()
        el2 = self.driver.find_element_by_xpath(
            "/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[2]/android.widget.RelativeLayout/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.widget.RelativeLayout[7]/android.widget.LinearLayout/android.widget.TextView")
        el2.click()

    def test_daka(self):
        # 打卡功能
        # 前提条件
        # 已登录状态( noReset = True)
        # 打卡用例:
        # 1、打开【企业微信】应用
        # 2、进入【工作台】
        self.driver.find_element(MobileBy.XPATH, "//*[@text='工作台']").click()
        # 3、点击【打卡】
        # 滚动查找 [打卡]
        self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,
                                 'new UiScrollable(new UiSelector().'
                                 'scrollable(true).instance(0)).'
                                 'scrollIntoView(new UiSelector().text("打卡")'
                                 '.instance(0));').click()
        # self.driver.update_settings({'waitForIdleTimeout':0})
        # 4、选择【外出打卡】tab
        self.driver.find_element(MobileBy.XPATH, "//*[@text='外出打卡']").click()
        # 5、点击【第N次打卡】
        self.driver.find_element(MobileBy.XPATH, "//*[contains(@text, '次外出')]").click()
        # 6、验证【外出打卡成功】
        self.driver.find_element(MobileBy.XPATH, "//*[@text='外出打卡成功']")
        # 7、退出【企业微信】应用

    def swipe_find(self, text):
        num = 3
        self.driver.implicitly_wait(1)
        for i in range(num):
            try:

                ele= self.driver.find_element(MobileBy.XPATH, f"//*[@text='{text}']")
                self.driver.implicitly_wait(5)
                return ele
            except:
                print("未找到")
                size = self.driver.get_window_size()
                # 'width', 'height'
                width = size.get('width')
                height = size.get("height")

                startx = width / 2
                starty = height * 0.8
                endx = startx
                endy = height * 0.3
                duration = 2000  # 单位是ms

                self.driver.swipe(startx, starty, endx, endy, duration)

            if i == 2:
                self.driver.implicitly_wait(5)
                raise NoSuchElementException()


    def test_addcontact(self):
        name = self.fake.name()
        phonenum = self.fake.phone_number()
        self.driver.find_element(MobileBy.XPATH, "//*[@text='通讯录']").click()
        # self.driver.find_element(MobileBy.XPATH, "//*[@text='添加成员']").click()
        self.swipe_find("添加成员").click()
        self.driver.find_element(MobileBy.XPATH, "//*[@text='手动输入添加']").click()
        # find_elements 返回元素列表[element1,element2,element3.....]
        self.driver.find_element(MobileBy.XPATH, "//*[contains(@text, '姓名')]/../*[@text='必填']").send_keys(name)
        self.driver.find_element(MobileBy.XPATH, "//*[contains(@text, '手机')]/..//*[@text='必填']").send_keys(phonenum)
        # self.driver.find_elements(MobileBy.XPATH, '//*[@text="必填"]')[1]
        self.driver.find_element(MobileBy.XPATH, "//*[@text='保存']").click()
        self.driver.find_element(MobileBy.XPATH, "//*[@text='添加成功']")
        # WebDriverWait(self.driver,10).until(lambda x:x.find_element(MobileBy.XPATH, "//*[@text='成功']"))
        # result= self.driver.find_element(MobileBy.CLASS_NAME, "android.widget.Toast").get_attribute('text')
        # print(result)
        # assert result == '添加成功'
        # sleep(2)
        # 获取页面的源代码
        # print(self.driver.page_source)

w3c find_element:
在这里插入图片描述
在这里插入图片描述
<-- 请求的返回

课堂练习

  • 删除联系人

二、企业微信实战(PO 封装)

1)传统测试用例的问题

  • 无法适应 UI 变化,UI 变化会导致大量的 case 需要修改
  • 大量的样板代码 driver find click
  • 无法清晰表达业务用例场景

2)PAGE OBJECT 模式六大原则

  • Selenium 官方提出六大原则
  1. 公共的方法代表页面提供的服务
  2. 不要暴露细节
  3. 不要把断言和操作细节混用
  4. 方法可以 return 到新打开的页面
  5. 不要把整页的内容都放到 PO 中
  6. 相同的行为会产生不同的结果,可以封装不同结果

3)PO 模式主要组成元素

  • Page 对象:完成对页面的封装
  • Driver 对象:完成对 web、android、ios、接口的驱动
  • 测试用例:调用 Page 对象实现业务并断言
  • 数据封装:配置文件和数据驱动
  • Utils:其他功能封装,改进原生框架不足
4)PO 模式 企业微信实战
  • 演练 App:企业微信 app
  • 演练语言:Python

三、框架改进方案

1)测试框架改进

  • BasePage 的封装
  • 初始化方法
  • find 方法
  • find_and_click 方法
  • handle_exception 方法

坑:Appium换命令行启动更稳定,可解决👇报错
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2)加入日志

  • 使用标准 log 取代 print
  • logging.baseConfig(level=logging.DEBUG)
  • 在具体的 action 中加入 log 方便追踪
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3)课后作业

  • 实现添加多个联系人功能的 PO 封装
  • 实现删除联系人功能的 PO 封装

  1. content-desc 与text值一致,一般国外app具有该属性(残障辅助) ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卢思小姐姐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值