欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

基于Appium+Pytest的UI自动化实例(Android)

程序员文章站 2022-03-12 12:32:48
基于Appium+Pytest的UI自动化实例(Android)环境配置1,...

基于Python3 Appium+Pytest的UI自动化实例(Android)

春有百花秋有月,夏有凉风冬有雪
若无闲事挂心头,便是人间好时节

  • 第一部分:所需环境的配置
  • 所需软件网盘链接(提取码1908):传送门
  • java1.8版本配置环境变量:
    1,JAVA_HOME D:\Software\Java\jdk1.8.0_231
    2,CLASSPATH .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
    3,Path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

  • AndroidSDK环境配置
    1,下载解压AndroidSDK后需要启动SDK Manager.exe下载所需的文件
    2,配置环境变量:
        ANDROID_HOME D:\SDK\android-sdk_r24.4.1-windows\android-sdk-windows
        path %ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools
        检验是否安装成功:adb / adb shell

  • appium环境
    1, appium desktop(appium server +appium inspector工具)
    2,appium server
        官方:npm install -g appium(需要爬墙)
        国内镜像:
        先安装NodeJs之后用npm安装cnpm:
        npm install -g cnpm --registry=https://registry.npm.taobao.org
        通过cnpm安装:cnpm install -g appium
        appium-docter: cnpm install appium-docter
    3,安装后输入appium进行检验是否成功,不报错说明成功
  • appium client(即使用的语言脚本)这里使用python
        通过pip安装:pip install appium-python-client
    ***到此就所有的环境准备完成!***
  • 第二部分:python测试脚本的编写
    以网易云音乐搜索为实例
    1,项目目录:
    基于Appium+Pytest的UI自动化实例(Android)
  • Page页面建模
  • basepage.py 内容:
from appium.webdriver.webdriver import WebDriver
from appium.webdriver.common.touch_action import TouchAction
import yaml
import pytest
from time import sleep

'''创建一个基础页面类,用于封装公共模块的处理方法
   和根据yaml配置文件进行案例的测试步骤'''


class BasePage:
    
    _blackList = []  # 黑名单列表,用于处理再case运行过程中可能出现的未知弹窗
    _errorCount = 0  # 定位元素的错误次数,元素定位中可能出现一次定位不到
    _errorMax = 5  # 允许进行元素定位的最大错误次数
    
    def __init__(self, driver: WebDriver = None):  # 初始化driver
        self._driver = driver
        
    def find(self, by, locator):  # $by>定位元素的方法,$locator>定位元素对应的所需value
        try:
            if isinstance(by, tuple):  # 如果传入的定位是个元组形式,包括方法和locator,就进行解包的方式定位
                element = self._driver.find_element(*by)
            else:
                element = self._driver.find_element(by, locator)
            self._errorCount = 0  # 找到元素,错误次数为0
            return element
        except Exception as e:
            self._errorCount += 1  # 未找到该元素,错误次数加1
            if self._errorCount >= self._errorMax:
                raise e  # 错误次数大于设置的最大次数抛出异常
            for black in self._blackList:
                elements = self._driver.find_elements(*black)  # 找到黑名单列表里的所有元素,[(by, locator),]的形式设置
                if len(elements) > 0:  # 出现弹框匹配黑名单列表大于0,即出现未知弹框
                    elements[0].click()  # 点击过后就找不到该元素了,所以永远点击第一个找到的就可以了
                    return self.find(by, locator)  # 点击后返回原方法,轮询去让定位可以继续执行
            raise e  # 没有找到,抛出异常
        
    def send(self, by, locator, value):  # 数据输入的方法
        try:
            self._driver.find(by, locator).send_keys(value)  # 定位到输入的位置,输入值
            self._errorCount = 0
        except Exception as e:
            self._errorCount += 1
            if self._errorCount >= self._errorMax:
                raise e  # 大于错误次数,抛出异常
            for black in self._blackList:
                elements = self._driver.find_element(*black)
                if len(elements) > 0:
                    elements[0].click()
                    return self.find(by, locator)
            raise e

    def steps(self, path):  # 定义操作步骤的方法,用于通过编写配置文件,执行相关用例
        with open(path, 'r', encoding='utf-8') as f:
            steps: list[dict] = yaml.safe_load(f)  # 操作步骤的数据类型为:[{},{}]
            # 遍历操作步骤
            for step in steps:
                if 'by' in step.keys():
                    element = self.find(step['by'], step['locator'])  # 定位到元素
                # 要进行的动作操作
                if 'action' in step.keys():
                    if 'click' == step['action']:  # 点击操作
                        element.click()
                    if 'send' == step['action']:
                        element.send_keys(step['value'])
                    if 'TouchAction' in step['action']:  # 滑动操作
                        action = TouchAction(self._driver)
                        action.press(x=step['value'][0]['x_start'], y=step['value'][0]['y_start']).wait(300)\
                            .move_to(x=step['value'][1]['x_end'], y=step['value'][1]['y_end']).release().perform()
                # 断言
                if 'assertion' in step.keys():
                    if "sleep" in step['assertion'].keys():
                        sleep(step['assertion']['sleep'])
                        element = self.find(step['assertion']['by'], step['assertion']['locator'])
                        attribute = element.get_attribute(step['assertion']['attribute'])
                        pytest.assume(attribute == step['assertion']['assert_info'])
                    if 'back' in step.keys():
                        self._driver.back()

  • app.py 内容:
from appium import webdriver
from Page.basepage import BasePage
from Page.main import Main


class App(BasePage):
    
    # 启动app
    def start(self):
        _package = "com.netease.cloudmusic"
        _activity = ".activity.LoadingActivity"
        if self._driver is None:
            desir_cap = {
                "appPackage": _package,
                "appActivity": _activity,
                "platformName": "Android",
                "platformVersion": "10",
                "dontStopAppOnReset": "true",
                "noReset": "true",
                "deviceName": "6de9e7a2"
            }
            self._driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desir_cap)
            self._driver.implicitly_wait(5)  # 隐式等待5s
        else:
            self._driver.start_activity(_package, _activity)
        return self
    def main(self):
        return Main(self._driver)
  • discovery.py 内容:因为是举例,所以以搜索为栗子
from Page.basepage import BasePage


# 发现page
class Discovery(BasePage):
    
    def daily_recommendation(self):
        self.steps("../TestData/discovery.yml")
  • main.py 内容
from Page.basepage import BasePage
from Page.discovery import Discovery


# 该类为进入不同页面(对<我的,发现,云村,视频>四个页面建模page的调配page
class Main(BasePage):
    
    def quit(self):
        self._driver.quit()
        
    def go_discover(self):  # 进入发现页
        self.steps('../TestData/main.yml')
        return Discovery(self._driver)
  • TestCase:测试案例
  • test_discoverypage.py 内容,发现page要进行的测试
from Page.app import App
import pytest


class TestDiscovery:
    
    def setup_class(self):
        self.testDriver = App().start().main()
        
    def teardown_class(self):
        self.testDriver.quit()
        
    def test_daily_recommendation(self):
        self.testDriver.go_discover().daily_recommendation()
  • TestData:测试数据配置文件(yaml)
  • main.yml
-
  by: accessibility id
  locator: 我的推荐

discovery.yml

-
  by: accessibility id
  locator: 搜索
  action: click
-
  by: id
  locator: com.netease.cloudmusic:id/search_src_text
  action: send
  value: 似是故人来
-
  by: id
  locator: com.netease.cloudmusic:id/adBannerView
  action: click

到此一个简单的PO模式的UI自动化测试就完成了,后边的一些其他类型的操作验证可以结合自己项目自行进行添加改进,本主也会更新完善该网易云实例的各种操作;谢谢观看!!!
欢迎请喝咖啡