深圳软件测试培训:Pytest+Appium+Allure 做 UI 自动化的那些事

文本主要介绍下 Pytest+Allure+Appium 记录一些过程和经历。
法主要用了啥:
Python3
Appium
Allure-pytest
Pytest
Appium 不常见却好用的方法
Appium 直接执行 adb shell 方法

Appium 启动时增加 --relaxed-security 参数 Appium 即可执行类似adb shell的方法

appium -p 4723 --relaxed-security

使用方法

def adb_shell(self, command, args, includeStderr=False):
“”"
appium --relaxed-security 方式启动
adb_shell(‘ps’,[’|’,‘grep’,‘android’])

:param command:命令
:param args:参数
:param includeStderr: 为 True 则抛异常
:return:
"""
result = self.driver.execute_script('mobile: shell', {'command': command,'args': args,'includeStderr': includeStderr,'timeout': 5000})
return result['stdout']

Appium 直接截取元素图片的方法
element = self.driver.find_element_by_id(‘cn.xxxxxx:id/login_sign’)
pngbyte = element.screenshot_as_png
image_data = BytesIO(pngbyte)
img = Image.open(image_data)
img.save(‘element.png’)

该方式能直接获取到登录按钮区域的截图

Appium 直接获取手机端日志

使用该方法后,手机端 logcat 缓存会清除归零,从新记录

建议每条用例执行完执行一边清理,遇到错误再保存减少陈余 log 输出

Android

logcat = self.driver.get_log(‘logcat’)

iOS 需要安装 brew install libimobiledevice

logcat = self.driver.get_log(‘syslog’)

web 获取控制台日志

logcat = self.driver.get_log(‘browser’)

c = ‘\n’.join([i[‘message’] for i in logcat])
allure.attach(c, ‘APPlog’, allure.attachment_type.TEXT)
#写入到 allure 测试报告中
Appium 直接与设备传输文件

发送文件

#Android
driver.push_file(’/sdcard/element.png’, source_path=‘D:\works\element.png’)

获取手机文件

png = driver.pull_file(’/sdcard/element.png’)
with open(‘element.png’, ‘wb’) as png1:
png1.write(base64.b64decode(png))

获取手机文件夹,导出的是zip文件

folder = driver.pull_folder(’/sdcard/test’)
with open(‘test.zip’, ‘wb’) as folder1:
folder1.write(base64.b64decode(folder))

iOS

需要安装 ifuse

> brew install ifuse 或者 > brew cask install osxfuse 或者 自行搜索安装方式

driver.push_file(’/Documents/xx/element.png’, source_path=‘D:\works\element.png’)

向 App 沙盒中发送文件

iOS 8.3 之后需要应用开启 UIFileSharingEnabled 权限不然会报错

bundleId = ‘cn.xxx.xxx’ # APP名字
driver.push_file(’@{bundleId}/Documents/xx/element.png’.format(bundleId=bundleId), source_path=‘D:\works\element.png’)

Pytest 与 Unittest 初始化上的区别
很多人都使用过 unitest 先说一下 pytest 和 unitest 在 Hook method上的一些区别
1.Pytest 与 unitest 类似,有些许区别,以下是 Pytest
class TestExample:
def setup(self):
print(“setup class:TestStuff”)

def teardown(self):print ("teardown          class:TestStuff")def setup_class(cls):print ("setup_class       class:%s" % cls.__name__)def teardown_class(cls):print ("teardown_class    class:%s" % cls.__name__)def setup_method(self, method):print ("setup_method      method:%s" % method.__name__)def teardown_method(self, method):print ("teardown_method   method:%s" % method.__name__)

2.使用 pytest.fixture()
@pytest.fixture()
def driver_setup(request):
request.instance.Action = DriverClient().init_driver(‘android’)
def driver_teardown():
request.instance.Action.quit()
request.addfinalizer(driver_teardown)
初始化实例
1.setup_class 方式调用
class Singleton(object):
“”“单例
ElementActions 为自己封装操作类”""
Action = None

def __new__(cls, *args, **kw):if not hasattr(cls, '_instance'):desired_caps={}host = "http://localhost:4723/wd/hub"driver = webdriver.Remote(host, desired_caps)Action = ElementActions(driver, desired_caps)orig = super(Singleton, cls)cls._instance = orig.__new__(cls, *args, **kw)cls._instance.Action = Actionreturn cls._instance

class DriverClient(Singleton):
pass
测试用例中调用
class TestExample:
def setup_class(cls):
cls.Action = DriverClient().Action

def teardown_class(cls):cls.Action.clear()def test_demo(self)self.Action.driver.launch_app()self.Action.set_text('123')

2.pytest.fixture() 方式调用
class DriverClient():

def init_driver(self,device_name):desired_caps={}host = "http://localhost:4723/wd/hub"driver = webdriver.Remote(host, desired_caps)Action = ElementActions(driver, desired_caps)return Action

该函数需要放置在 conftest.py, pytest 运行时会自动拾取

@pytest.fixture()
def driver_setup(request):
request.instance.Action = DriverClient().init_driver()
def driver_teardown():
request.instance.Action.clear()
request.addfinalizer(driver_teardown)
测试用例中调用
#该装饰器会直接引入driver_setup函数
@pytest.mark.usefixtures(‘driver_setup’)
class TestExample:

def test_demo(self):self.Action.driver.launch_app()self.Action.set_text('123')

Pytest 参数化方法
1.第一种方法 parametrize 装饰器参数化方法
@pytest.mark.parametrize((‘kewords’), [(u"小明"), (u"小红"), (u"小白")])
def test_kewords(self,kewords):
print(kewords)

多个参数

@pytest.mark.parametrize(“test_input,expected”, [
(“3+5”, 8),
(“2+4”, 6),
(“6*9”, 42),
])
def test_eval(test_input, expected):
assert eval(test_input) == expected
2.第二种方法,使用 pytest hook 批量加参数化

conftest.py

def pytest_generate_tests(metafunc):
“”"
使用 hook 给用例加加上参数
metafunc.cls.params 对应类中的 params 参数

"""
try:if metafunc.cls.params and metafunc.function.__name__ in metafunc.cls.params: ## 对应 TestClass paramsfuncarglist = metafunc.cls.params[metafunc.function.__name__]argnames = list(funcarglist[0])metafunc.parametrize(argnames, [[funcargs[name] for name in argnames] for funcargs in funcarglist])
except AttributeError:pass

test_demo.py

class TestClass:
“”"
:params 对应 hook 中 metafunc.cls.params
“”"
# params = Parameterize(‘TestClass.yaml’).getdata()

params = {'test_a': [{'a': 1, 'b': 2}, {'a': 1, 'b': 2}],'test_b': [{'a': 1, 'b': 2}, {'a': 1, 'b': 2}],
}
def test_a(self, a, b):assert a == b
def test_b(self, a, b):assert a == b

Pytest 用例依赖关系
使用 pytest-dependency 库可以创造依赖关系
当上层用例没通过,后续依赖关系用例将直接跳过,可以跨 Class 类筛选
如果需要跨.py 文件运行 需要将 site-packages/pytest_dependency.py 文件的
class DependencyManager(object):
“”“Dependency manager, stores the results of tests.
“””

ScopeCls = {'module':pytest.Module, 'session':pytest.Session}@classmethod
def getManager(cls, item, scope='session'): # 这里修改成 session

如果

pip install pytest-dependency
class TestExample(object):

@pytest.mark.dependency()
def test_a(self):assert False@pytest.mark.dependency()
def test_b(self):assert False@pytest.mark.dependency(depends=["TestExample::test_a"])
def test_c(self):# TestExample::test_a 没通过则不执行该条用例# 可以跨 Class 筛选print("Hello I am in test_c")@pytest.mark.dependency(depends=["TestExample::test_a","TestExample::test_b"])
def test_d(self):print("Hello I am in test_d")

pytest -v test_demo.py
2 failed
- test_1.py:6 TestExample.test_a
- test_1.py:10 TestExample.test_b
2 skipped
Pytest 自定义标记,执行用例筛选作用
1.使用 @pytest.mark 模块给类或者函数加上标记,用于执行用例时进行筛选
@pytest.mark.webtest
def test_webtest():
pass

@pytest.mark.apitest
class TestExample(object):
def test_a(self):
pass

@pytest.mark.httptest
def test_b(self):pass

仅执行标记 webtest 的用例
pytest -v -m webtest

Results (0.03s):
1 passed
2 deselected
执行标记多条用例
pytest -v -m “webtest or apitest”

Results (0.05s):
3 passed
仅不执行标记 webtest 的用例
pytest -v -m “not webtest”

Results (0.04s):
2 passed
1 deselected
不执行标记多条用例
pytest -v -m “not webtest and not apitest”

Results (0.02s):
3 deselected
2.根据 test 节点选择用例
pytest -v Test_example.py::TestClass::test_a
pytest -v Test_example.py::TestClass
pytest -v Test_example.py Test_example2.py
3.使用 pytest hook 批量标记用例

conftet.py

def pytest_collection_modifyitems(items):
“”"
获取每个函数名字,当用例中含有该字符则打上标记
“”"
for item in items:
if “http” in item.nodeid:
item.add_marker(pytest.mark.http)
elif “api” in item.nodeid:
item.add_marker(pytest.mark.api)
class TestExample(object):
def test_api_1(self):
pass

def test_api_2(self):passdef test_http_1(self):passdef test_http_2(self):pass
def test_demo(self):pass

仅执行标记 api 的用例
pytest -v -m api
Results (0.03s):
2 passed
3 deselected
可以看到使用批量标记之后,测试用例中只执行了带有 api 的方法
用例错误处理截图,app 日志等
1.第一种使用 python 函数装饰器方法
def monitorapp(function):
“”"
用例装饰器,截图,日志,是否跳过等
获取系统log,Android logcat、ios 使用syslog
“”"

@wraps(function)
def wrapper(self, *args, **kwargs):try:allure.dynamic.description('用例开始时间:{}'.format(datetime.datetime.now()))function(self, *args, **kwargs)self.Action.driver.get_log('logcat')except Exception as E:f = self.Action.driver.get_screenshot_as_png()allure.attach(f, '失败截图', allure.attachment_type.PNG)logcat = self.Action.driver.get_log('logcat')c = '\n'.join([i['message'] for i in logcat])allure.attach(c, 'APPlog', allure.attachment_type.TEXT)raise Efinally:if self.Action.get_app_pid() != self.Action.Apppid:raise Exception('设备进程 ID 变化,可能发生崩溃')
return wrapper

2.第二种使用 pytest hook 方法 (与方法一选一)
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
Action = DriverClient().Action
outcome = yield
rep = outcome.get_result()
if rep.when == “call” and rep.failed:
f = Action.driver.get_screenshot_as_png()
allure.attach(f, ‘失败截图’, allure.attachment_type.PNG)
logcat = Action.driver.get_log(‘logcat’)
c = ‘\n’.join([i[‘message’] for i in logcat])
allure.attach(c, ‘APPlog’, allure.attachment_type.TEXT)
if Action.get_app_pid() != Action.apppid:
raise Exception(‘设备进程 ID 变化,可能发生崩溃’)
Pytest 另一些 hook 的使用方法
1.自定义 Pytest 参数

pytest -s -all

content of conftest.py

def pytest_addoption(parser):
“”"
自定义参数
“”"
parser.addoption("–all", action=“store_true”,default=“type1”,help=“run all combinations”)

def pytest_generate_tests(metafunc):
if ‘param’ in metafunc.fixturenames:
if metafunc.config.option.all: # 这里能获取到自定义参数
paramlist = [1,2,3]
else:
paramlist = [1,2,4]
metafunc.parametrize(“param”,paramlist) # 给用例加参数化

怎么在测试用例中获取自定义参数呢

content of conftest.py

def pytest_addoption(parser):
“”"
自定义参数
“”"
parser.addoption("–cmdopt", action=“store_true”,default=“type1”,help=“run all combinations”)

@pytest.fixture
def cmdopt(request):
return request.config.getoption("–cmdopt")

test_sample.py 测试用例中使用

def test_sample(cmdopt):
if cmdopt == “type1”:
print(“first”)
elif cmdopt == “type2”:
print(“second”)
assert 1

pytest -q --cmdopt=type2
second
.
1 passed in 0.09 seconds
2.Pytest 过滤测试目录
#过滤 pytest 需要执行的文件夹或者文件名字
def pytest_ignore_collect(path,config):
if ‘logcat’ in path.dirname:
return True #返回 True 则该文件不执行

Pytest 一些常用方法
Pytest 用例优先级(比如优先登录什么的)

pip install pytest-ordering
@pytest.mark.run(order=1)
class TestExample:
def test_a(self):
Pytest 用例失败重试
#原始方法
pytet -s test_demo.py
pytet -s --lf test_demo.py #第二次执行时,只会执行失败的用例
pytet -s --ll test_demo.py #第二次执行时,会执行所有用例,但会优先执行失败用例
#使用第三方插件
pip install pytest-rerunfailures #使用插件
pytest --reruns 2 # 失败case重试两次
Pytest 其他常用参数
pytest --maxfail=10 #失败超过10次则停止运行
pytest -x test_demo.py #出现失败则停止

深圳软件测试培训:Pytest+Appium+Allure 做 UI 自动化的那些事相关推荐

  1. 【自动化测试】Pytest+Appium+Allure 做 UI 自动化的那些事

    文本主要介绍下 Pytest+Allure+Appium 记录一些过程和经历. 法主要用了啥: Python3 Appium Allure-pytest Pytest Appium 不常见却好用的方法 ...

  2. 用 Pytest+Appium+Allure 做 UI 自动化测试的那些事儿

    本文首发于 TesterHome 社区, 文末有福利 !链接 https://testerhome.com/topics/19327 前言 做 UI 自动化测试有段时间了,在 TesterHome 社 ...

  3. 深圳软件测试培训:软件测试的需求评审

    深圳软件测试培训:软件测试的需求评审 需求评审 1.需求阶段评审的角色和职责 一句话,根据具体情况选择相关人员,充当相关角色,履行相关职责,大家也别吐槽我,现实就是这样,别去记忆这些死规则了 2.好的 ...

  4. 深圳软件测试培训:自动化测试

    深圳软件测试培训:自动化测试 自动化测试指软件测试的自动化,在预设状态下运行应用程序或系统,预设条件包括正常和异常,最后评估运行结果.将人为驱动的测试行为转化为机器执行的过程. 自动化测试框架一般可以 ...

  5. 深圳软件测试培训:Jmeter目录构成

    深圳软件测试培训:Jmeter目录构成 Jmeter的Home目录下包含bin.docs.extras等文件夹, 需要重点了解的是bin.lib和docs目录 Bin目录下存放的是可执行的程序.配置文 ...

  6. 深圳软件测试培训:软件生命周期(SDLC)的六个阶段

    深圳软件测试培训:软件生命周期(SDLC)的六个阶段 1.问题的定义及规划 此阶段是软件开发方与需求方共同讨论,主要确定软件的开发目标及其可行性. 2.需求分析 在确定软件开发可行的情况下,对软件需要 ...

  7. 深圳软件测试培训:软件测试技术及工具

    深圳软件测试培训:软件测试技术及工具 一.软件测试的发展史 1979年,Glenford Myers的<软件测试艺术>,对测试做了定义:测试是为发现错误而执行的一个程序或者系统的过程.19 ...

  8. 深圳软件测试培训:移动测试ExpandableListView

    深圳软件测试培训:移动测试ExpandableListView 一.ExpandableListView: (一).类结构: java.lang.Object ↳ android.view.View ...

  9. 深圳软件测试 黑盒测试,深圳软件测试培训:常用控件黑盒测试方法有哪些?...

    深圳软件测试培训(sz.qa.tedu.cn)专家就针对常用控件黑盒测试方法有哪些这一问题做一个详细的分解.希望能在工作中对你有所帮助! 1.常用控件有哪些 文本框,复选框,按钮,单选按钮,列表框,组 ...

最新文章

  1. 金融风控实战——信贷评分卡
  2. c++ 如何判断无效指针_如果链表中有环,我们应该如何判断?
  3. 数据结构【图】—022邻接矩阵的深度和广度遍历
  4. OpenGL球体的Phong渲染
  5. 数据挖掘—K-中心点聚类算法(Java实现)
  6. 前端学习(778):随机数方法
  7. 【OpenCV】OpenCV实战从入门到精通之 -- 图像对比度、亮度值调整
  8. activeMQ入门安装
  9. 安全公司本意告警用户,不料先遭攻击并泄露超50亿个人数据
  10. 配置IIS Express 7.5以允许外部访问
  11. 善用工具和网上资源-决定学习的效率
  12. halcon学习资料
  13. 【时间序列】时间序列数据的缺失填补方法总结
  14. WebSphere 环境搭建
  15. idea双击打不开的解决方案
  16. 传奇服务器端显示时间问题,架设传奇出现is not a valid date and time时间错误
  17. 联想thinkpad待机怎么唤醒_笔记本睡眠怎么唤醒【步骤介绍】
  18. 正则表达式(三)正则的捕获
  19. 1G~5G的关键技术和技术标准
  20. ScrollBar ScrollWindow

热门文章

  1. 典范杜希奇与机器人_典范英语8-16doohickey and the robot杜希奇与机器人
  2. HTML+CSS+JavaScript 实现登录注册页面(超炫酷)
  3. Vue爬坑之旅(二十一):vue使用富文本编辑器vue-quill-editor实现配合后台将图片上传至七牛
  4. iOS音频系列(一)--音频基础
  5. ArchLinux+Win10安装美化及一些常用(装逼神器)软件安装记
  6. HTTP contentType
  7. 借名买房规避限购政策的,合同应认定为无效
  8. 完美解决Tomcat启动一闪而过
  9. css元素发光效果图,纯CSS3实现圆圈动态发光特效动画的示例代码
  10. linux学习系列-常用命令的使用