• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用 Pytest 运行 yaml 文件来驱动 Appium 自动化测试

武飞扬头像
自由家
帮助1

目录

前言:

获取 yaml 文件

YamlTest 测试类

Appium 初始化

Pytest 测试类

自定义 runtest demo:

自定义错误输出

Yaml 使用方式规则


前言:

使用Pytest来运行yaml文件来驱动Appium自动化测试是一种方便且灵活的方法。通过将测试数据和测试逻辑分离,您可以更轻松地管理和扩展测试用例。

本文主要介绍一下 pytest hook 方法是怎么运行 yaml 文件做测试的 (喜欢其他方式也可以用 xlsx,sql 等),怎么与 Appium 结合,来驱动 Appium 做自动化测试。

该运行方式参照 pytest --doctest 参数运行的方法, 想深入了解的同学可以查看 _pytest/doctest.py 源码

获取 yaml 文件

使用 pytest_collect_file 钩子函数,在脚本运行之前过滤 .yml 文件

  1.  
    def pytest_collect_file(parent, path):
  2.  
    # 获取文件.yml 文件
  3.  
    if path.ext == ".yml" and path.basename.startswith("test"):
  4.  
    return YamlFile(path, parent)

读取 yml 转成 json 移交至 YamlTest 类

  1.  
    class YamlFile(pytest.File):
  2.  
    # 读取文件内容
  3.  
    def collect(self):
  4.  
    import yaml
  5.  
    raw = yaml.safe_load(self.fspath.open(encoding='utf-8'))
  6.  
    for name, values in raw.items():
  7.  
    yield YamlTest(name, self, values)

YamlTest 测试类

下面就是测试类了,这里我们 Appium 还是使用单例初始化,方便所有测试用例继承一个 session

Appium 初始化

  1.  
    class Singleton(object):
  2.  
    """单例
  3.  
    ElementActions 为自己封装操作类"""
  4.  
    Action = None
  5.  
     
  6.  
    def __new__(cls, *args, **kw):
  7.  
    if not hasattr(cls, '_instance'):
  8.  
    desired_caps={}
  9.  
    host = "http://localhost:4723/wd/hub"
  10.  
    driver = webdriver.Remote(host, desired_caps)
  11.  
    Action = ElementActions(driver, desired_caps)
  12.  
    orig = super(Singleton, cls)
  13.  
    cls._instance = orig.__new__(cls, *args, **kw)
  14.  
    cls._instance.Action = Action
  15.  
    return cls._instance
  16.  
     
  17.  
    class DriverClient(Singleton):
  18.  
    pass
  19.  
     
学新通

Pytest 测试类

测试类初始化,这里要说一下,测试类一定要继承 pytest.Item 方法

  1.  
    class YamlTest(pytest.Item):
  2.  
    def __init__(self, name, parent, values):
  3.  
    super(YamlTest, self).__init__(name, parent)
  4.  
    self.values = values
  5.  
    self.Action = DriverClient().Action # 初始化 Appium
  6.  
    self.locator = None
  7.  
     

为了减少代码的逻辑,取出来的 yaml json 字符串怎么可以直接转化成可运行方法呢?

这里就要说到 class 的 _getattribute_ 内建属性的用法,下面举个简单例子

  1.  
    class TestExample:
  2.  
    def test1(self):
  3.  
    print('test1')
  4.  
     
  5.  
    >>> TestExample().__getattribute__('test1')()
  6.  
    test1

现在我们就能直接读取 yaml 文件中的 method 字符串直接转化成 Appium api 运行了(method 对应自己封装或 Appium api 的方法)

自定义 runtest demo:

  1.  
    class YamlTest(pytest.Item):
  2.  
    def __init__(self, name, parent, values):
  3.  
    super(YamlTest, self).__init__(name, parent)
  4.  
    self.values = values
  5.  
    self.Action = DriverClient().Action
  6.  
    self.locator = None
  7.  
     
  8.  
    def runtest(self):
  9.  
    # 运行用例
  10.  
    for self.locator in self.values:
  11.  
    self.locator['time'] = 5
  12.  
    if self.locator.get('element'):
  13.  
    # 需要接收参数
  14.  
    response = self.Action.__getattribute__(self.locator.get('method'))(self.locator)
  15.  
    else:
  16.  
    # 不需要参数
  17.  
    response = self.Action.__getattribute__(self.locator.get('method'))()
  18.  
    self.assert_response(response, self.locator)
  19.  
     
  20.  
     
学新通

这里将 Appium api 基本操作封装成了两类:

  • 需要接收元素的参数,例如:点击,查找,输入等
  • 不需要接收元素参数,例如:重启,滑动等

自定义错误输出

  1.  
    def repr_failure(self, excinfo):
  2.  
    """自定义报错信息,如果没有定义则会默认打印错误堆栈信息,因为比较乱,所以这里自定义一下 """
  3.  
     
  4.  
    if isinstance(excinfo.value, Exception):
  5.  
    return '测试用例名称:{} \n' \
  6.  
    '步骤输入参数:{} \n' \
  7.  
    '数据:{}'.format(self.name, self.locator, excinfo.value.args)
  8.  
     
  9.  
    def reportinfo(self):
  10.  
    return self.fspath, 0, "CaseName: %s" % self.name

下面就是完整的测试类了

  1.  
    class YamlTest(pytest.Item):
  2.  
    def __init__(self, name, parent, values):
  3.  
    super(YamlTest, self).__init__(name, parent)
  4.  
    self.values = values
  5.  
    self.Action = DriverClient().Action
  6.  
    self.locator = None
  7.  
     
  8.  
    def runtest(self):
  9.  
    # 运行用例
  10.  
    for self.locator in self.values:
  11.  
    self.locator['time'] = 5
  12.  
    is_displayed = True
  13.  
    if not self.locator.get('is_displayed'):
  14.  
    is_displayed = False if str(self.locator.get('is_displayed')).lower() == 'false' else True
  15.  
    try:
  16.  
    if self.locator.get('element'):
  17.  
    response = self.Action.__getattribute__(self.locator.get('method'))(yamldict(self.locator))
  18.  
    else:
  19.  
    response = self.Action.__getattribute__(self.locator.get('method'))()
  20.  
    self.assert_response(response, self.locator)
  21.  
    except Exception as E:
  22.  
    if is_displayed:
  23.  
    raise E
  24.  
    pass
  25.  
     
  26.  
    def repr_failure(self, excinfo):
  27.  
    """自定义报错信息,如果没有定义则会打印堆栈错误信息,调试时可以注释该函数,便于问题查找 """
  28.  
    if isinstance(excinfo.value, Exception):
  29.  
    return '测试类名称:{} \n' \
  30.  
    '输入参数:{} \n' \
  31.  
    '错误信息:{}'.format(self.name, self.locator, excinfo.value.args)
  32.  
     
  33.  
    def assert_response(self, response, locator):
  34.  
    if locator.get('assert_text'):
  35.  
    assert locator['assert_text'] in response
  36.  
    elif locator.get('assert_element'):
  37.  
    assert response
  38.  
     
  39.  
    def reportinfo(self):
  40.  
    return self.fspath, 0, "CaseName: %s" % self.name
学新通

Yaml 使用方式规则

因为我们上面将接收方法分成了需要 element 参数和不需要 element 参数两类所以 yaml 格式如下

  1.  
    test_index:
  2.  
    -
  3.  
    method: launchApp # 启动 APP
  4.  
    -
  5.  
    method: 方法名称 例如:click (必填)
  6.  
    element: 查找元素id,class等 (选填,配合 method 如需要点击元素,查找元素等必填)
  7.  
    type: 元素类型 id,xpath,class name,accessibility id (选填,会自动识别,如识别错误则自行填写)
  8.  
    name: 测试步骤的名称 例如:点击搜索按钮 (选填)
  9.  
    text: 需要输入或者查找的文本 (选填,配合部分 method 使用)
  10.  
    time: 查找该元素需要的时间,默认 5s (选填)
  11.  
    index: 页面有多个id,class时,不为空则查找元素数组下标 (选填)
  12.  
    is_displayed: 默认 True ,当为 False 时元素未找到也不会抛异常(选填)

咱们用微博做个 demo 测试一下

  1.  
    test_index:
  2.  
    -
  3.  
    method: launchApp # 重启 APP
  4.  
    -
  5.  
    method: click
  6.  
    element: click_ad_skip
  7.  
    name: 广告跳过按钮
  8.  
    is_displayed: False
  9.  
    -
  10.  
    method: click
  11.  
    element: 发现
  12.  
    name: 导航发现按钮
  13.  
    -
  14.  
    method: sleep
  15.  
    element: 3
  16.  
    -
  17.  
    method: set_text
  18.  
    element: com.sina.weibo:id/tv_search_keyword
  19.  
    text: testerhome
  20.  
    name: 搜索输入框
  21.  
    -
  22.  
    method: set_keycode_enter
  23.  
    -
  24.  
    method: screenshot_element
  25.  
    element: //*[@resource-id="com.sina.weibo:id/lv_content"]/android.widget.RelativeLayout[1]
  26.  
    name: 搜索内容截图
学新通

运行用例

pytest -v ./test_case/test_ranking.yml --alluredir /report/test

或者直接运行文件目录

使用方法和基本 pytest 用法没有太大区别

pytest -v ./test_case --alluredir /report/test

来查看下运行结果:

学新通

学新通

  作为一位过来人也是希望大家少走一些弯路

在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。

(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等)

相信能使你更好的进步!

点击下方小卡片

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfjbacj
系列文章
更多 icon
同类精品
更多 icon
继续加载