Pytest测试框架

Pytest测试框架

pytest介绍

  • pytest是一个非常成熟的全功能的python测试框架
    • 简单灵活,易上手
    • 可以参数化
    • 可支持简单的单元测试和负载的功能测试,还可以与selenium/appnium做自动化测试,接口测试可与request结合
    • 支持与jenkins集成 devops
    • 特殊用法:skip和xfail,自动失败处理机制

样例

def fun(x):
    return x + 1

def test_answer():
    assert fun(3) ==5

黑窗口执行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest安装方式以及第三方库结合使用

  • pip install -U pytest U升级pytest
  • pip install pytest-sugar 美化管理台的数据
  • pip install pytest-rerunfailures 测试案例失败后重新尝试执行
  • pip install pytest-xdist 分布式执行和多线程执行
  • pip install pytest-assume 测试案例有多条断言,一条失败不影响下一条的断言
  • pip install pytest-html 生成测试报告

测试用例的识别与运行

  • 测试文件
    • test_*.py
    • *_test.py
  • 用例识别
    • Test*类包含的所有test_*的方法(测试类不能带有__init__方法)
    • 不在class中的所有test_*方法
  • pytest也可以执行unittest框架写的用例和方法

终端执行的常用参数

  • pytest /py.test
  • pytest -v 打印详细运行日志信息
  • pytest -v -s 文件名 打印日志信息以及测试案例中管理台输出语句的内容
  • pytest 文件名.py 执行单独一个pytest模块
  • pytest 文件名.py::类名 运行某个文件中的某个类
  • pytest 文件名.py::类名::方法名 运行某个文件中某个类的某个方法
  • pytest -v -k ‘类名 and not 方法名’ 跳过运行某个用例
  • pytest -m [标记名] 运行pytest.mark[标价名]的测试用例
  • pytest -x 文件名 一旦运行出错停止运行
  • pytest --maxfail=[num] 当运行中出现了num的失败的案例书就停止运行

测试代码

def test_one():
    print("开始执行 test_one用法")
    a = 'this'
    assert 'h' in a


def test_two():
    print("开始执行 test_two放啊")
    x = 'hello'
    assert 'e' in x


def test_three():
    print("开始执行 test_three方法")
    a = 'hello'
    b = 'hello world'
    assert a in b

###运行方式一

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行方式二

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行方式三

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

###测试代码二

class TestDemo():
    def test_one(self):
        print("开始执行 test_one用法")
        a = 'this'
        assert 'h' in a

    def test_two(self):
        print("开始执行 test_two放啊")
        x = 'hello'
        assert 'e' in x

    def test_three(self):
        print("开始执行 test_three方法")
        a = 'hello'
        b = 'hello world'
        assert a not in b


class TestDemo1():
    def test_a(self):
        print("开始执行 test_a用法")
        a = 'this'
        assert 'h' in a

    def test_b(self):
        print("开始执行 test_b放啊")
        x = 'hello'
        assert 'e' in x

    def test_c(self):
        print("开始执行 test_c方法")
        a = 'hello'
        b = 'hello world'
        assert a in b

执行方式一

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行方式二

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行方式四

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行方式五

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行方式六

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest执行失败-重新运行

  • 场景
    • 测试失败后要重新运行n次,要在重新运行之前添加延迟时间,间隔n秒在运行
  • 安装:
    • pip install pytest-rerunfailures
  • 执行
    • pytest -reruns 3 -v -s xxx.py
    • pytest -v --reruns 5 --reruns-delay 1
  • 一定要用命令行安装插件,会减少丢包的操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest执行-多条断言有失败也都运行

  • 场景:一个方法中写多天断言,如果第一条断言失败,会导致方法发下的其它断言都无法执行
  • 安装
    • pip install pytest-assume
  • 执行:
    • pytest.assume(1==4)
    • pytest.assume(2==4)
安装

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试代码
import pytest


class TestDemo():
    def test_one(self):
        print("开始执行 test_one用法")
        a = 'this'
        assert 'h' in a
        pytest.assume(1 == 2)
        pytest.assume(1 == 3)

    def test_two(self):
        print("开始执行 test_two放啊")
        x = 'hello'
        assert 'e' in x

    def test_three(self):
        print("开始执行 test_three方法")
        a = 'hello'
        b = 'hello world'
        assert a not in b


class TestDemo1():
    def test_a(self):
        print("开始执行 test_a用法")
        a = 'this'
        assert 'h' in a

    def test_b(self):
        print("开始执行 test_b放啊")
        x = 'hello'
        assert 'e' in x

    def test_c(self):
        print("开始执行 test_c方法")
        a = 'hello'
        b = 'hello world'
        assert a in b


if __name__ == '__main__':
    pytest.main()
执行方式+结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试用例的识别与运行(IDE工具中)

  • pycharm配置与执行pytest测试框架
  • 运行方式:
    • pytest.main([‘-v’,‘测试类’]) (传的参数与pytest命令行方式是一样的)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest框架结构

  • import pytest 类似的setup,teardown同样更灵活
    • 模块级(setup_module/teardown_module)模块始末,全局的(优先级最高
    • 函数级(setup_function/teardown_function)只对函数用例生效(不在类中叫函数
    • 类级(setup_class/teardown_class)指在类中前后运行一次
    • 方法级(setup_method/teardown_method)开始于方法始末
    • 类里面的(setup/teardown)运行在调用方法的前后
实战代码
import pytest


def setup_module():
    print("这个是setup_module方法")


def teardown_module():
    print("这个是teardown_module方法")


def setup_function():
    print("这个是setup_function方法")


def teardown_function():
    print("这个是teardown_function方法")


def test_login():
    print("这是一个外部的方法")


class TestDemo():
    def setup_class(self):
        print("这是一个setup_class方法")

    def teardown_class(self):
        print("这是一个teardown_class方法")

    def setup_method(self):
        print("这是一个setup_method方法")

    def teardown_method(self):
        print("这是一个teardown_method方法")

    def setup(self):
        print("这是一个setup方法")

    def teardown(self):
        print("这是一个teardown方法")

    def test_one(self):
        print("开始执行 test_one用法")
        a = 'this'
        assert 'h' in a
        # pytest.assume(1 == 2)
        # pytest.assume(1 == 3)

    def test_two(self):
        print("开始执行 test_two放啊")
        x = 'hello'
        assert 'e' in x

    def test_three(self):
        print("开始执行 test_three方法")
        a = 'hello'
        b = 'hello world'
        assert a not in b

# if __name__ == '__main__':
#     pytest.main()

运行后展示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest-fixture的用法

  • 场景:
    • 用例一需要先登录
    • 用例二不需要登录
    • 用例三需要登录
  • 这种场景无法用setup与teardown实现
  • 用法
    • 在方法前面加@pytest.fixture()
应用场景:前端自动化中应用
  • 场景:测试用例执行时,有的用例需要登陆才能执行,有些不需要登录。setup和teardown无法满足。fixture可以,默认scope(范围)function
  • 实现步骤
    • 导入pytest
    • 在登陆的函数上加@pytest.fixture()
    • 在要使用的测试方法中传入(登录函数名称)就先登陆
    • 不传入的就不登陆直接执行测试方法
实战
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pytest


@pytest.fixture()
def login():
    print("这是个登录方法")


def test_case1(login):
    print("test_case1")


def test_case12(login):
    print("test_case2")


def test_case3(login):
    print("test_case3")


if __name__ == '__main__':
    pytest.main()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

前端自动化中应用-conftest

  • 场景:
    • 协同开发的时候,公共要在不同文件中,要在大家都访问到的地方
  • 解决
    • conftest.py这个文件进行数据共享,并且可以放在不同位置起着不同的范围共享作用
  • 执行:
    • 系统执行到参数login时先从本地文件中查找是否有这个名字的变量,之后再conftest.py中找是否存在
  • 步骤:
    • 将登陆模块的函数上加@pytest.fixture()写在conftest.py中
  • conftest文件配置注意事项
    • 首先文件名必须是conftest
    • conftest.py与运行的用例在同一个package下,并且有__init__.py文件
    • 不需要导入conftest.py,pytest用例会自动查找的
    • 全局的配置和前期工作都可以写在这里,放在具体某个包下,就是这个包的数据共享的地方
实战
#!/usr/bin/env/ python
# -*- coding: utf-8 -*-

import pytest


# 不带参数的fixture默认参数为 scope=function
@pytest.fixture()
def login():
    print("这是登陆方法")


def pytest_configure(config):
    mark_list = ["search", "login"]  # 标签名集合
    for markers in mark_list:
        config.addinivalue_line(
            "markers", markers
        )

前端自动化中应用-yield

  • 场景:通过conftest已经可以将用例执行前的依赖解决,但是执行后的销毁清除数据要如何进行?范围是模块级别的。类似setupclass
  • 解决:
    • 通过在同一模块中加入yield关键字,yield时调用第一次返回结果,第二次执行它下面的语句返回
  • 步骤:
    • 在@pytest.fixture(scope=module)
  • 在登陆的方法中加yield,之后加销毁清除的步骤需要注意,这种方式没有返回值,如有希望返回值需要使用addfinalizer
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest


# 作用域:module是在模块之前执行,模块之后执行
@pytest.fixture(scope="module")
def open():
    print("打开浏览器")
    yield

    print("执行teardown!")
    print("最后关闭浏览器")


def test_search1(open):
    print("test_case1")
    raise NameError


def test_search2(open):
    print("test_case2")
    # raise NameError


def test_search3(open):
    print("test_case3")
    # raise NameError


if __name__ == '__main__':
    pytest.main()
运行后代码截图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

fixture的自动应用

  • 场景
    • 不想原测试方法有任何改动,或全部都自动实现自动应用,没特例,也都不需要返回值时可以选择自动应用
  • 解决:
    • 使用fixture中参数autouse=True
  • 步骤:
    • 在方法上加@pytest.fixture(autouse=True)
    • 在测试方法上加@pytest.mark.usefixtures(“start”)
代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest


@pytest.fixture(autouse=True)
def open():
    print("打开浏览器")

    print("执行teardown!")
    print("最后关闭浏览器")


def test_search1():
    print("test_case1")
    raise NameError


def test_search2():
    print("test_case2")
    # raise NameError


def test_search3():
    print("test_case3")
    # raise NameError


if __name__ == '__main__':
    pytest.main()
执行后代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

fixture带参数传递

  • 场景:测试离不开数据,为了数据灵活,一般数据都是通过参数传递的
  • 解决:fixture通过固定参数request传递
  • 步骤:
    • 在fixture中增加@pytest.fixture(params=[1,2,3,‘linda’])在方法参数写request
代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest


@pytest.fixture(params=[1, 2, 3, 'linda'])
def test_data(request):
    return request.param


def test_one(test_data):
    print('\ntest data: %s ' % test_data)
执行后代

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进阶代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys

import pytest


# 参数化 前两个变量,后面是对应的数据
# 3+5 -> test_input 8->expect
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+5", 7), ("7+5", 30)])
def test_eval(test_input, expected):
    # eval 将字符串str当成有效的表达式求值,并返回结果
    assert eval(test_input) == expected


# 参数组合
@pytest.mark.parametrize("y", [8, 10, 11])
@pytest.mark.parametrize("x", [1, 2])
def test_foo(x, y):
    print(f"测试数据组合x:{x},y:{y}")


# 方法名作为参数
test_user_data = ['Tome', 'jerry']


@pytest.fixture(scope='module')
def login_r(request):
    # 这是接受并传入的参数
    user = request.param
    print(f"\n打开首页准备登录,登录用户:{user}")
    return user


# indirect=True 可以把传过来的参数当函数执行
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值{a}")
    assert a != ""


# indirect=True 可以把传过来的参数当函数执行
@pytest.mark.skip("此次测试不执行登录")
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值{a}")
    assert a != ""


# sys.platform == "win32"  获取当前系统型号
@pytest.mark.skipif(sys.platform == "win32", reason="不在win上执行")
# indirect=True 可以把传过来的参数当函数执行
# @pytest.mark.skip("此次测试不执行登录")
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值{a}")
    assert a != ""


# 当前案例不执行直接给xpass
@pytest.mark.xfail
# indirect=True 可以把传过来的参数当函数执行
# @pytest.mark.skip("此次测试不执行登录")
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值{a}")
    assert a != ""


# 当前案例不执行直接给xfail
@pytest.mark.xfail
# indirect=True 可以把传过来的参数当函数执行
# @pytest.mark.skip("此次测试不执行登录")
@pytest.mark.parametrize("login_r", test_user_data, indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值{a}")
    assert a != ""
    raise NameError

mark中的skip与xfail

  • Skip使用场景
    • 测试时不想运行这个用例
    • 标记无法在某平台上运行的测试功能
    • 在某些版本上执行,其他版本中跳过
    • 当前的外部资源不可用时跳过(如数据库不可用的时候)
  • 解决:
    • @pytest.mark.skip(跳过这个测试用例,或者可以加skipif,在满足条件下才希望执行)
  • xfail场景
    • 功能测试尚未实现修复的缺陷,当测试通过时尽管会失败(@pytest.mark.xfail),他是一个xpass,将在测试报告中显示摘要
    • 你希望测试由于某种原因就应该失败 加一个 raise 错误类型
  • 解决:
    • @pytesr.mark.xfail
代码在上面的一张图片中

使用自定义标记mark只执行某部份用例

  • 场景:
    • 只执行符合要求的某一部分用例,可以把一个web项目分多个模块,然后指定模块去执行
    • App自动化时,如果想Android和OS共用一部分代码时,也可以使用标记功能,标明哪些时OS的用例,哪些是adnroid的运行代码时指定mark名称运行
  • 解决:
    • 在测试用例方法上加@pytest.mark.webtest(webtest这个可自定义)
  • 执行:
    • -s参数:输出所有测试用例的print信息
    • -m:执行自定义标记的相关用例
      • pytest -s test.py -m=webtest
      • pytest -s test.py -m=apptest
      • pytest -s test.py -m “not ios”
#!/usr/bin/env python
# -*- coding: utf-8  -*-
import pytest


@pytest.mark.search
def test_search1():
    print("test_search1")
    raise NameError


@pytest.mark.search
def test_search2():
    print("test_search2")


@pytest.mark.search
def test_search3():
    print("test_search3")


@pytest.mark.login
def test_login1():
    print("test_login1")


@pytest.mark.login
def test_login2():
    print("test_login2")


@pytest.mark.login
def test_login3():
    print("test_login3")


if __name__ == '__main__':
    pytest.main()
执行后命令

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标记执行案例提示waning警告解决办法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#!/usr/bin/env/ python
# -*- coding: utf-8 -*-

import pytest


# 不带参数的fixture默认参数为 scope=function
@pytest.fixture()
def login():
    print("这是登陆方法")

# 解决warn报错的方法,将标记的后缀加入以下列表中即可,固定写法
def pytest_configure(config):
    mark_list = ["search", "login"]  # 标签名集合
    for markers in mark_list:
        config.addinivalue_line(
            "markers", markers
        )
以上代码要放到confftest文件中才可生效

多线程并行与分布式执行

  • 场景:

    • 测试用例1000条,一个用例执行1分钟,一个测试人员需要1000分钟,这样效率太低
  • 解决:

    • pytest分布式执行插件:pytest-xdist多个CPU或主机运行

      前提案例之间无依赖

  • 安装:

    • pip3 install pytest-xdist
    • 多个CPU并行执行用例,直接加-n 3是并行数量:pytest -n 3
    • 在多个终端下一起执行
执行后代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest-html生成报告

  • 安装:pip install pytest-html
  • 生成html报告:pytest -v -s --html=report.html --self-contained-html
执行代码后

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打开这个文件即可

pytest数据参数化

  • 使用方法
    • @pytest.mark.parametrize(argnames,argualues)
    • argnames:要参数化的变量,string(逗号分隔),list,tuple
    • argvalues:参数化的值,list,list[tuple]

使用string

@pytest.mark.parametrize("a,b",[(10,20),(10,30)])

def test_param(a,b): print(a+b)

使用list

@pytest.mark.paramterize(["a","b"],{(10,20),(10,30)})

def test_param(a,b): print(a+b)

使用tuple

@pytest.mark.paramterize(("a","b"),[(10,20),(20,30)])

def test_param(a,b): print(a+b)

代码练习
import pytest


# 使用字符串
class TestData:
    @pytest.mark.parametrize("a,b", [(1, 2), (2, 3), (3, 4)])
    def test_data(self, a, b):
        print(a + b)


# 使用元组
class TestData1:
    @pytest.mark.parametrize(("a", "b"), [(1, 2), (2, 3), (3, 4)])
    def test_data(self, a, b):
        print(a + b)


# 使用列表
class TestData2:
    @pytest.mark.parametrize(["a", "b"], [(1, 2), (2, 3), (3, 4)])
    def test_data(self, a, b):
        print(a + b)
执行后截图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

yaml基本使用

  • yaml实现list

    • -list
      • -10
      • -20
      • -30
  • yaml实现字典

    • dict
      • by:id
      • locator:name
      • action:click
  • yaml进行嵌套1

    • -
      • -by:id
      • -locator:name
      • -actiong:click
  • yaml进行嵌套2

    • companies:
    • -
      • id:1
      • name:company1
      • price:200$
    • -
      • id:2
      • name:company2
      • price:500$

    格式:companies:[{id:1,name:company1,price:200$},{}]

加载yaml文件

yanl.safe_load(open("./data.yaml"))

加载yanl

@pytest.mark.paramterize(["a","b"],yaml.safe(open("./data.yaml")))

def test_param(a,b): print(a+b)

代码练习
import pytest
import yaml


# 使用yaml
class TestData:
    @pytest.mark.parametrize("a,b", yaml.safe_load(open("./data.yaml")))
    def test_data(self, a, b):
        print(a + b)
-
  - 10
  - 20
-
  - 10
  - 20

python数据驱动

数据驱动简介

数据驱动是数据的改变从而驱动自动化测试的执行;最终引起结果的改变。

应用场景

  • App/Web/接口自动化测试
    • 测试步骤的数据驱动
    • 测试数据的数据驱动
    • 配置的数据驱动

###数据驱动案例

import pytest

import yaml


class TestDemo:
    @pytest.mark.parametrize("env",yaml.safe_load(open("./env.yaml")))
    def test_demo(self, env):
        print(env)
        if "test" in env:
            print(f"测试环境地址{env['test']}")
        elif "dev" in env:
            print("开发环境")

if __name__ == '__main__':
    pytest.main(["-v","-s"])
-
  test: 127.0.0.1

Allure测试框架

allure介绍

  • allure是一个轻量级、灵活的,支持多语言的测试报告工具
  • 多平台的奢华的report框架
  • 可以为dev/qa提供详尽的测试报告,测试步骤、log
  • 为管理层提供high level统计报告
  • Java语言开发的,支持pytest,Javascript,php,ruby等
  • 可以集成到Jenkins

allure安装

  • 国内下载地址:https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/

  • 配置环境变量

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pytest-allure插件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Allure报告的生成

  • 安装allure-pytest插件
    • pip install allure-pytest
  • 运行
    • 在测试执行期间收集结果
    • pytest [测试文件] -s -q -alluredir=./result(–alluredir这个选项用于存储测试结果的路径)
    • 查看测试报告
      • 方式一:测试完成后查看实际报告,在线看报告,会直接打开默认浏览器的展示当前的报告
        • allure serve ./result/ 踩坑:serve的书写
      • 方式二:从结果生成报告,这是一个启动tomcat的服务,需要两个步骤,生成报告,打开报告
        • 生成报告
          • allure generate ./result/ -o ./report/ --clean(注意:覆盖路径加–clean)
        • 打开报告
          • allure open -h 127.0.0.1 -p 8889 ./report/
实战代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pytest


def test_success():
    """this test success"""
    assert True


def test_failure():
    """this test fail"""
    assert False


def test_skip():
    """this test is skipped"""
    pytest.skip("for a reason")


def test_broken():
    raise Exception('oops')
执行方式一

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

执行方式二

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

allure特性分析

  • 场景:
    • 希望在报告中看到测试功能,子功能或场景,测试步骤,包括测试附加信息
  • 解决:
    • @Feature,@story,@step,@attach
  • 步骤:
    • import allure
    • 功能上加@allure.feature(“功能名称”)
    • 子功能上加@allure.story(“子功能名称”)
    • 步骤上加@allure.step(“步骤名称”)
    • @allure.attach(“具体文本信息”),需要附加的信息,可以是数据、文本、图片、视频、、网页
    • 如果只测试登录功能运行的时候可以限制过滤
      • pytest 文件名 --allure-features “购物车功能” --allure-stories “加入购物车” (–allure_feature中间是下划线)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
import allure


@allure.feature("登录模块")
class TestLogin():
    @allure.story("登录成功")
    def test_login_success(self):
        print("这是登录:测试用例,登陆成功")

    @allure.story("登录失败")
    def test_login_success_a(self):
        print("这是登录:测试用例,登登录成功")

    @allure.story("用户名缺失")
    def test_login_success_b(self):
        print("用户名缺失")

    @allure.story("密码缺失")
    def test_login_failure(self):
        with allure.step("点击用户名"):
            print("输入用户名")
        with allure.step("点击密码"):
            print("输入密码")
        print("点击登录")
        with allure.step("点击登录之后登陆失败"):
            assert '1' == 1
            print("登录失败")

    @allure.story("登录失败")
    def test_login_failure_a(self):
        print("这是登录:测试用例,登陆失败")
报告生成流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

allure特性-feature/story

  • 注解@allure.feature与@allure.store的关系
    • feture相当于一个功能,一个大的模块,将case分类到某个feature中显示,相当于behaviore中显示,相当于testcase
    • story相当于对应这个功能或者模块下的不同场景,分支功能,属于feature之下的结构,报告在features中显示,相当于testcase
    • feature与story蕾西与父子关系

按feature/story运行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

allure特性-step

  • 测试过程中每个步骤,一般放在其具体逻辑方法中
  • 可以放在实现步骤中,在报告中显示
  • 在app/web自动测试中,建议每切换到一个新的页面当作一个step
  • 用法:
    • @allure.skip()只能以装饰器的形式放在类或方法上面
    • with allure.step():可以放在测试用例方法里面,但测试步骤的代码需要被该语句包含
allure特性-issue,testcase
  • 关联测试用例(可以直接给测试用例的地址链接)
  • 关联bug
    • 执行的时候需要加上个参数
    • –allure-link-pattern=issue:具体地址
代码

@allure.issue('140','')

def test_with_link():

pass

Test_case_link="具体地址" @allure.testcase(Test_case_link,"Test case title") def test_with_testcase_link(): pass

代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import allure


@allure.link("http://www.baidu.com", name="百度链接")
def test_with_link():
    print("这是一个加了链接的测试")


TEST_CASE_LINK = "http:...."


@allure.testcase(TEST_CASE_LINK, "登录用例")
def test_with_testcase_link():
    print("这是一条测试用例的链接,链接到测试用例")


# --allure-link-pattern=issue:http://www.mytesttracker.com/issue/{}
@allure.issue('140', '这是一个issue')
def test_with_issue_link():
    pass
运行方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行后截图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按重要性级别进行一定范围的测试

  • 场景:
    • 通常测试有Po、冒烟测试,验证上线测试,按重要性级别分别执行的,比如上线要把主流程和重要模块都跑一遍
  • 解决:
    • 通过附加pytest.mark标记
    • 通过allure.feature,allure.story
    • 也可以通过allure.severity来附加标记
      • 几倍Trivial不重要,Minor不太重要,Normal正常问题,Critical严重,Blocker:阻塞
  • 步骤:
    • 在方法函数和类上面加
      • @pytest.severity(allure.severity_level.TRIVIAL)
    • 执行时
      • pytest -s -v 文件名 --allure-severities normal,critical
  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import allure


def test_with_no_severity_label():
    pass


@allure.severity(allure.severity_level.TRIVIAL)
def test_with_trivial_severity():
    pass


@allure.severity(allure.severity_level.NORMAL)
def test_with_normal_severity():
    pass


@allure.severity(allure.severity_level.NORMAL)
class TestClassWithNormalSeverity(object):
    def test_inside_the_normal_severity_test_class(self):
        pass

    @allure.severity(allure.severity_level.CRITICAL)
    def test_inside_the_normal_severity_test_class_with_overriding_critical_severity(self):
        pass
执行后截图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过IDE执行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

前端自动化测试截图
  • 场景:
    • 前端自动化测试经常需要附加图片或html,在适当的低昂,适当的实际截图
  • 解决:
    • @allure.attach显示许多不同类型的提供的附件,可以补充测试,步骤或测试结果
  • 步骤:
    • 在测试报告中附加网页:
      • allure.attach(body(内容),name,attachment_type,extension)
      • allure.attach(‘html语言’,‘这是错误信息’,allure.attachment_type.HTML)
    • 在测试报告中附加图片
      • allure.attach.file(source,name,attachment_type,extension)
      • allure.attach.file(‘,/result/photo.png’,attachment_type=allure.attachment_type.PNG)
代码

```PYTHON
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import allure


def test_attach_text():
    allure.attach("这是一个纯文本", attachment_type=allure.attachment_type.TEXT)


def test_attach_html():
    allure.attach("""<body>这是一个htmlbody模块</body>) 
               """, "html模块", allure.attachment_type.HTML)


def test_attach_photo():
    allure.attach.file("C:/Users/Administrator/Desktop/pytesy框架/1.png", name="截图",
                       attachment_type=allure.attachment_type.PNG)

    # allure.description("这条测试用例是用来说明allure的description)allure-pytest+selenium实战演示
```

##### 执行后截图

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CLocal%5CTemp%5C1724632110704.png&pos_id=img-aAuRj34g-1725267687491)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CLocal%5CTemp%5C1724632075765.png&pos_id=img-FAq8avPr-1725267687522)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CLocal%5CTemp%5C1724632088071.png&pos_id=img-SGOBZBZs-1725267687524)

#### 实战

```python
#!/bin/env/ python
# -*- coding: utf-8 -*-
import allure

import pytest

from selenium import webdriver

import time

from selenium.webdriver.common.by import By


@allure.feature('百度搜索')
@pytest.mark.parametrize('test_detail', ['allure', 'pytest', 'unittest'])
def test_steps_demo(test_detail):
    with allure.step("打开百度网页"):
        driver = webdriver.Chrome()
        driver.get("http://www.baidu.com")
        driver.maximize_window()
    with allure.step(f"输入搜索词{test_detail}"):
        driver.find_element(By.ID, "kw").send_keys(test_detail)
        time.sleep(2)
        driver.find_element(By.ID, 'su').click()
        time.sleep(2)
    with allure.step("保存图片"):
        driver.save_screenshot("./result/baidu/b.png")
        allure.attach.file("./result/baidu/b.png", attachment_type=allure.attachment_type.PNG)
        allure.attach('<head></head><body>首页</body>', 'attach with HTML type', allure.attachment_type.HTML)
    with allure.step("关闭浏览器"):
        driver.quit()
```

##### 执行

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CLocal%5CTemp%5C1724634108792.png&pos_id=img-a3JIrJhg-1725267687526)

cription("这条测试用例是用来说明allure的description)allure-pytest+selenium实战演示
```

##### 执行后截图

[外链图片转存中...(img-aAuRj34g-1725267687491)]

[外链图片转存中...(img-FAq8avPr-1725267687522)]

[外链图片转存中...(img-SGOBZBZs-1725267687524)]

#### 实战

```python
#!/bin/env/ python
# -*- coding: utf-8 -*-
import allure

import pytest

from selenium import webdriver

import time

from selenium.webdriver.common.by import By


@allure.feature('百度搜索')
@pytest.mark.parametrize('test_detail', ['allure', 'pytest', 'unittest'])
def test_steps_demo(test_detail):
    with allure.step("打开百度网页"):
        driver = webdriver.Chrome()
        driver.get("http://www.baidu.com")
        driver.maximize_window()
    with allure.step(f"输入搜索词{test_detail}"):
        driver.find_element(By.ID, "kw").send_keys(test_detail)
        time.sleep(2)
        driver.find_element(By.ID, 'su').click()
        time.sleep(2)
    with allure.step("保存图片"):
        driver.save_screenshot("./result/baidu/b.png")
        allure.attach.file("./result/baidu/b.png", attachment_type=allure.attachment_type.PNG)
        allure.attach('<head></head><body>首页</body>', 'attach with HTML type', allure.attachment_type.HTML)
    with allure.step("关闭浏览器"):
        driver.quit()
```

##### 执行

[外链图片转存中...(img-a3JIrJhg-1725267687526)]

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CLocal%5CTemp%5C1724634130338.png&pos_id=img-EhpEceOT-1725267687528)
  • 12
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值