PYTHON+AIRTEST+PYTEST控制多款手机实现APP UI自动化[转载]

PYTHON+AIRTEST+PYTEST控制多款手机实现APP UI自动化

标签: APP 自动化  python  多进程

python+airtest+pytest 实现多款APP UI 自动化
如果代码有什么问题,欢迎指出(毕竟我也是新手)
自从找不到工作,就只能看看APP自动化程序了,增加下知识

壹、原理:

使用poco 库+多进程 连接多款手机进行操作

贰、用到的库:

  1. poco (airtest的库)
pip install poco

2.pocoui

pip install pocoui

3.airtest

pip install airtest

4.pytest

pip install -U pytest 

5.pytest-html(报告模块)

pip3 install pytest-html -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

6.pytest-repeat (重复测试用例的模块)

pip3 install pytest-repeat -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

7.allure (也是报告)

pip3 install allure-pytest -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

叁:文件目录:


目录详解(下文没说的文件是不重要的文件)
1.config_dy – config.py 一些文件目录集中在一个文件,方便修改

import  os
import  datetime
# 项目根目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
# 日志目录
LOG_DIR = os.path.join(BASE_DIR, 'dy_log')
# 截图文件
SCRE_DIR = os.path.join(BASE_DIR, 'until_dy\screen')
#当前时间
NOW_TIME = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
# 运行文件
RUN_DIR = os.path.join(BASE_DIR, 'until_dy\pro_main.py')
if __name__ == '__main__':
    print(RUN_DIR)

2.config_dy – config.ini 页面元素配置文件
3.config_dy --dy_config 读取ini 配置文件

# -*- coding: gbk -*-
import  configparser
import  os
class Page_config(object):
    def __init__(self):
        # os.path.dirname 去掉文件名 返回目录
        # os.path.realpath(__file__)  范围当前文件目录包括文件名
        BASE_DIR = os.path.dirname(os.path.realpath(__file__))
        ZHEN_DIR = os.path.join(BASE_DIR, 'config.ini')
        self.file = ZHEN_DIR
        self.config = configparser.ConfigParser()
        self.config.read(self.file)
    # 获得所有section 列表返回
    def getAllSections(self):
        return self.config.sections()
    # 获得所有option 列表返回
    def getAllOptions(self, section):
        return self.config.options(section)
    # 获取指定option 的值, 以字典格式返回
    def getOnesection(self,section,option):
        try:
            locator =self.config.get(section,option)
            if option  in self.config.options(section):
                locator = {option:locator}
                # locator = dict(self.config.items())
            return locator
        except configparser.NoOptionError as e:
            return  e
          # return 'error: No option "{}" in section: "{}"'.format(option, section)
if __name__ == '__main__':
    page = Page_config()
    print(page.getOnesection('douyin_page','guanzhu'))

4.config_dy --openexcel.py 用来读取本地excel 文件。有很多测试数据就用这个读取

# -*- coding: gbk -*-
# 解析excel
# 获取的数据为 字符串
import xlrd
import os

class OpneExcel(object):
    def __init__(self,path):
        self.path = path
        self.wk  = xlrd.open_workbook(self.path)  if  '测试用例.xlsx' in os.path.basename(self.path) else None
        self.data = self.wk.sheet_by_name('Sheet1')
    # 获取数据总行数
    def getnrows(self):
        return self.data.nrows
    # 获取数据总列数
    def getncols(self):
        return self.data.ncols
    # 获取指定行 区间数据
    # colx索引是从0 开始的
    def getnrows_math(self,colx, start, end):
        return self.data.col_values(colx , start_rowx=start, end_rowx=end)
    # 获取某一列数据
    def getonecols(self, colx):
        if colx > self.data.ncols:
            return '没有那么多列'
        else:
            return self.data.col_values(colx)
    # 获取指定行列对应数据
    # 获取数据的索引是从0开始的
    def get_ncmath(self,nrows, ncols):
        return self.data.cell_value(nrows, ncols)
    # 获取多列数据
    def getooneclos(self,*colx):
        result = []
        if len(colx) == 0:
            return '空'
        else:
            for i in colx:
                result.append(self.data.col_values(i))
            return  result
if __name__ == '__main__':
    op =  OpneExcel('D:\\测试用例.xlsx')
    print(op.get_ncmath(1,1))

5.dy_log --loggin_dy 日志文件

import logging
import  os
import datetime
from  config_dy.conf import *
'''
%(asctime)s 字符串形式的当前时间。
%(name)s Logger的名字
%(levelname)s 文本形式的日志级别
%(message)s 用户输出的消息
'''
class Log(object):
    def __init__(self, clevel=logging.INFO):
        self.clevel = clevel
        self.path = os.path.join(LOG_DIR,"{}.log".format(self.nowtime()))
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(level=self.clevel)
        self._contorl()

    def _contorl(self):
        if not self.logger.handlers:
            handler = logging.FileHandler(self.path,'a', encoding="utf-8")
            handler.setLevel(self.clevel)
            self.fromatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(self.fromatter)
            self.logger.addHandler(handler)
    # 时间
    def nowtime(self):
        now_time = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
        return str(now_time)

if __name__ == '__main__':
    print(Log()._contorl())

6.until_dy --conftest 全局公用文件(详解会在另外一篇文件中)
特点:

  • 共文件内的py 文件调用,解决一个方法重复利用的问题,可以被多个py文件调用
  • 运行时,程序先检查是否存在此文件,存在先运行这个文件
  • 不需要import,可以直接引用
  • 名称是固定的,不能改变
  • 文件内报告多个fixture 文件

7.until_dy – connect_iphone.py 用来连接手机

因为用到多进程,此文件已经没有,连接手机已经和多进程卸载一起

from  poco.drivers.android.uiautomation import  AndroidUiautomationPoco
from airtest.core.api import  * #  connect_device()  start_app()  clear_app()

import  time

class Open_iphone(object):
    def __init__(self):
        self.poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)

    def start_app_1(self):
    	# 链接手机
        connect_device('Android:///R28M30RXKNZ')
        # 什么都不填写,会默认取当前连接中的第一台手机
		connect_device('Android:///')
		# 连接本机默认端口连的一台设备号为79d03fa的手机  没试验过
		connect_device('Android:///127.0.0.1:5037/79d03fa')
		# 连接一个Windows窗口,窗口句柄为123456      没试验过
		connect_device('Windows:///123456')
		# 启动APP
        start_app('App名称')
        
    def clearr_app(self):
        clear_app('App名称')

7.until_dy – pro_dong.py 操控手机动作文件
8.until_dy – pro_main.py 测试用例1
9.until_dy --run.py 主要运行文件
文件内容:

  1. 本来要用队列存放设备号,但是奈何身边只有两个手机,利用率不高,就把设备号放到了公共变量里面(gl._int())
  2. 多进程控制多款手机,没用线程,因为线程之间******(一个线程挂了,全都要挂,用不起,用不起),所以没用。
# -*- coding: gbk -*-
import pytest
import  os
from  until_dy import globalvar as gl
import pytest
from  config_dy.conf import  *
import subprocess
from airtest.core.api import *
from multiprocessing import  Pool
import  multiprocessing
import allure
gl._int()  # 公共变量,用来存放设备号
q = multiprocessing.Queue()

# 分配adb, 链接手机,放到队列里面,先进先出
def creat_devices():
	# 非阻塞行为
    devices = subprocess.Popen('adb devices', shell=True, stdout=subprocess.PIPE)
    de = []

    for i in devices.stdout.readlines()[1:-1]:
        de.append(str(i)[2:-5].replace(r'\tdevice',''))
    allure.attach(f'设备的参数{de}')

def run_wenjian():
    # print('fu',os.getpid())
    # print('name{}-{}'.format(name, os.getpid()))
    pytest.main(['-s', '-q','pro_main.py', '--alluredir', 'report/xml'])
    # pytest.main(["-s", '-v', 'pro_main.py', "--html=report_dy/{}.html".format(os.getpid())
    #              ])

# 多少个手机 多少个进程,进程池设置为3 USB连接不稳定 '
def make_process():
    print('zhu', os.getpid())
    print()
    pool = Pool(3)
    # for i in range(2):
    pool.apply_async(run_wenjian)
    pool.close()
    pool.join()

if __name__ == '__main__':
    gl.set_value(creat_devices())
    make_process()


版权声明:本文为OYangGouDai原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:python+airtest+pytest控制多款手机实现APP UI自动化_OYangGouDai的博客-CSDN博客_python+airtest

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值