超级详细的pytest测试和allure测试报告

1、pytest可以识别执行的测试文件包括

test_*.py
_test.py
都可以识别该文件
测试用例识别:Test
类包含的所有test_*的方法(测试类不能带有__init__方法);不在class中的所有的test_*方法都可以识别

2、安装直接使用pip install -U pytest命令安装即可

3、pytest -k可以指定匹配运行某个测试测试用例,后面再加上-v可以查看某个测试用例的详细执行结果
pytest --collect-only 只收集测试用例
pytest -m mark 标签名 标记
超级详细的pytest测试和allure测试报告_第1张图片
我们看到有一个warning,产生的原因是这些标签不是可以识别的,那么我们怎么处理这个warning呢,我们可以创建一个pytest.ini文件进行注册这个标签,自定义标签名,内容如下
[pytest]
markers = case1
超级详细的pytest测试和allure测试报告_第2张图片
我们再次运行试下发现warning没有了
超级详细的pytest测试和allure测试报告_第3张图片
pytest.ini配置文件是pytest的主配置文件,一般放在项目工程的根目录,它可以指定pytest的运行方式,并且不能使用任何的中文符号
测试用例模块test_a.py:

class Test_A():

    def test_case_a(self):
        print(f"测试用例A")
        assert 6 > 5

    def test_case_b(self):
        print(f"测试用例B")
        assert 9 > 7

测试用例模块check_b.py:

class Check_B():

    def aaa_case_a(self):
        print(f"测试用例A---")
        assert 6 > 5

    def aaa_case_b(self):
        print(f"测试用例B---")
        assert 9 > 7

我们新建一个pytest.ini文件,来指定运行check开头的测试用例和模块
[pytest]
python_files = check_*
python_classes = Check_*
python_functions = aaa_*
超级详细的pytest测试和allure测试报告_第4张图片
运行pytest -v -s
超级详细的pytest测试和allure测试报告_第5张图片
可以看出只收集到了两条测试用例,分别是check_b.py模块下的两条测试用例,符合我们的预期
因为在执行pytest的时候,会首先执行我们的配置文件pytest.ini文件,所以我们可以在配置文件里面配置我们想要运行的命令,假设我们增加addopts = -v -s --alluredir=./result,如下
超级详细的pytest测试和allure测试报告_第6张图片
我们直接运行pytest
超级详细的pytest测试和allure测试报告_第7张图片
我们也可以忽略某些文件夹,使用norecursedirs = 运行时忽略某些文件夹,后面写上要忽略的文件夹名称
pytest框架结构
模块级别(setup_module/teardown_module)全局的
函数级别(setup_function/teardown_function)只对函数用例生效,在类外面
类级(setup_class/teardown_class)只在类中前后运行一次
方法级(setup_method/teardown_method)开始于方法始末,在类里面
类里面的(setup/teardown)运行在调用方法的前后

4、参数化

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

import pytest

def inc(x):
    return x + 1

@pytest.mark.parametrize('a,b',[(1,2),(5,6),(7,8),(9,10)])
def test_answer_01(a,b):
    assert inc(a) == b

运行结果:
超级详细的pytest测试和allure测试报告_第8张图片
yaml实现参数化
yaml实现list

list
	- 10
	- 20
	- 30

yaml实现字典

dict
	by:id
	locator:name
	action:click

yaml进行嵌套一

-
	- by:id
	- locator:name
	- action:click

yaml进行嵌套二

companies:
	-
		id:1
		name:lili
		age:16
	-
		id:2
		name:youyou
		age:18

我们先安装yaml这个库
超级详细的pytest测试和allure测试报告_第9张图片
使用如下进行加载yaml内容

import pytest
import yaml

def inc(x):
    return x + 1

@pytest.mark.parametrize(("a","b"),yaml.safe_load(open("./data.yaml")))
def test_answer_01(a,b):
    assert inc(a) == b

数据文件:

-
  - 1
  - 2
-
  - 3
  - 4
-
  - 6
  - 7
-
  - 10
  - 11

运行结果:
超级详细的pytest测试和allure测试报告_第10张图片

5、场景一:假设测试用例在执行前需要登陆,那么我们可以在执行前调用登录的方法,前提是要定义一个登陆方法,并且使用fixture进行装饰,同时,在测试用例中,也能够接收登陆函数的返回

@pytest.fixture()
def login():
    print("要开始登陆了哈")
    username = "xiongda"
    return username

class Test_A:

    def test_answer_02(self,login):
        print(f"test_answer_02  login={login}")

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

运行结果:
超级详细的pytest测试和allure测试报告_第11张图片

场景二:在与其他测试工程师一起合作的时候,公共的模块要在不同的文件中 可以使用conftest.py这个文件进行数据共享,它放在不同位置起着不同范围的共享作用;当前conftest这个文件的文件名是不能变化的。

conftest.py的作用域是:对当前同级目录下所有的文件及包下的所有测试文件,测试方法生效,如果同级目录下没有conftest.py,会找上级目录或者上上级目录 的conftest.py里的fixture方法。
我们新建一个conftest.py文件
超级详细的pytest测试和allure测试报告_第12张图片
内容如下:

import pytest

@pytest.fixture()
def login():
    print("这个是公共的方法")
    return "公共方法"

test_a.py文件内容

class Test_A():

    def test_case01(self,login):
        print(f"测试用例1 {login}")

    def test_case02(self):
        print("测试用例2")

    def test_case03(self):
        print("测试用例3")

    def test_case04(self):
        print("测试用例4")

我们运行test_case01这个测试用例,发现也能运行成功
超级详细的pytest测试和allure测试报告_第13张图片

场景三:我们可以使用scope来控制setup和teardown的作用域和范围

修改conftest.py文件如下

import pytest

@pytest.fixture(scope = "class")
def login():
    print("这个是公共的方法")
    yield "公共方法"  #yield激活fixture  teardown方法
    print("teardown")

运行整个test_a.py这个模块
超级详细的pytest测试和allure测试报告_第14张图片
注意:scope = "session"表示在整个目录中只执行一次
scope = "moudle"表示每一个模块也就是每个.py文件执行一次

场景四:不想让原有的测试方法有所改动,想让每一个测试用例都运行公共的方法,我们可以使用autouse

修改condtest.py文件如下:@pytest.fixture(autouse=True)

import pytest

@pytest.fixture(autouse=True)
def login():
    print("这个是公共的方法")
    yield "公共方法"  #yield激活fixture  teardown方法
    print("teardown")
class Test_A():

    def test_case01(self, login):
        print(f"测试用例1 {login}")

    def test_case02(self):
        print(f"测试用例2")

    def test_case03(self):
        print(f"测试用例3")

    def test_case04(self):
        print("测试用例4")

我们可以看到每一个测试用例都用到了公共的方法
超级详细的pytest测试和allure测试报告_第15张图片

场景五:为了使数据更加灵活,一般数据都是通过参数进行传递的,我们可以通过fixture固定参数request传递

修改conftest.如下

import pytest


@pytest.fixture(autouse=True, params=["user1", "user2", "user3"])
def login(request):
    print("这个是公共的方法")
    print(request.param)
    yield ["user", "name"]  #yield激活fixture  teardown方法
    print("teardown")
class Test_A():

    def test_case01(self):
        print(f"测试用例1")

    def test_case02(self):
        print(f"测试用例2")

    def test_case03(self):
        print(f"测试用例3")

    def test_case04(self):
        print("测试用例4")

运行结果:
超级详细的pytest测试和allure测试报告_第16张图片
我们可以看到每一个测试用例下面都使用了这几个参数,和参数化功能相差不多

场景六:fixture与参数化相结合,传入一个fixture方法,将数据传入到fixture方法中,fixture方法使用request参数来接收这组数据

conftest.py:

import pytest

@pytest.fixture()
def login(request):
    print("这个是公共的方法")

test_a.py

import pytest

class Test_A():

    @pytest.mark.parametrize("login", [(1, 1), (3, 3), (5, 5)], indirect = True)
    def test_case01(self, login):
        print(f"测试用例1")

运行结果:
超级详细的pytest测试和allure测试报告_第17张图片
超级详细的pytest测试和allure测试报告_第18张图片

pytest实用的插件介绍

pip install pytest-ordering 控制用例的执行顺序

pytest的默认执行顺序是自上向下执行(注意pytest多个装饰器的时候可能会发生冲突),如果要调整顺序,我们可以使用@pytest.mark.run(order=1),如果不小心标记成了相同的顺序,测试用例就按照自上而下执行了
代码如下:

import pytest

class Test_A():

    @pytest.mark.run(order=3)
    def test_case01(self):
        print(f"测试用例1")
        assert 2 > 1

    @pytest.mark.run(order=2)
    def test_case02(self):
        print(f"测试用例2")
        assert 2 > 0

    @pytest.mark.run(order=1)
    def test_case03(self):
        print(f"测试用例3")
        assert 28 > 12

运行结果:
超级详细的pytest测试和allure测试报告_第19张图片

pip install pytest-dependency 控制用例的依赖关系

@pytest.mark.dependency(depends=[依赖的测试用例名称])
比如说测试用例C对测试用例A和测试用例B都有依赖关系,我们希望只有当测试用例A和测试用例B都执行通过后,才去执行C,否则跳过C
超级详细的pytest测试和allure测试报告_第20张图片
假设测试用例D也依赖与测试用例A
当测试用例A失败的时候,测试用例C和测试用例D都会直接跳过,如下:

import pytest

class Test_A():

    @pytest.mark.dependency()
    def test_case_a(self):
        print(f"测试用例A")
        assert 2 > 5

    @pytest.mark.dependency()
    def test_case_b(self):
        print(f"测试用例B")
        assert 2 > 0
    @pytest.mark.dependency(depends=['test_case_a', 'test_case_b'])
    def test_case_c(self):
        print(f"测试用例C")
        assert 28 > 12

    @pytest.mark.dependency(depends=['test_case_a'])
    def test_case_d(self):
        print(f"测试用例D")
        assert 28 > 12

    def test_case_e(self):
        print(f"测试用例E")
        assert 28 > 12

运行结果如下:
超级详细的pytest测试和allure测试报告_第21张图片
当测试用例A运行通过,测试用例B运行不通过的时候,测试用例C运行不会通过,测试用例D和测试用例E运行通过,如下:

import pytest

class Test_A():

    @pytest.mark.dependency()
    def test_case_a(self):
        print(f"测试用例A")
        assert 6 > 5

    @pytest.mark.dependency()
    def test_case_b(self):
        print(f"测试用例B")
        assert 2 > 7
    @pytest.mark.dependency(depends=['test_case_a', 'test_case_b'])
    def test_case_c(self):
        print(f"测试用例C")
        assert 28 > 12

    @pytest.mark.dependency(depends=['test_case_a'])
    def test_case_d(self):
        print(f"测试用例D")
        assert 28 > 12

    def test_case_e(self):
        print(f"测试用例E")
        assert 28 > 12

运行结果:
超级详细的pytest测试和allure测试报告_第22张图片

pip install pytest-xdist 分布式并发执行测试用例

测试用例一共有100条,一个执行1分钟,就需要100分钟,如果并行测试10个人一起执行时间就会缩短,这就是一种并行测试,分布式场景;
此方法的应用存在一定的原则,第一,就是用例之间是相互独立的,用例之间没有相互依赖关系,用例可以完全独立运行;第二,用例执行没有顺序,随机顺序都能正常执行;第三,每个测试用例都能重复运行,运行结果不会影响其他测试用例
此应用方式测试用例较多的时候测试效果明显,在执行过程中使用pytest -n 3命令进行执行
示例中的执行效果不明显
超级详细的pytest测试和allure测试报告_第23张图片

pip install pytest-rerunfailures 失败重跑

使用命令pytest test_a.py --reruns 5 --reruns-delay 1 -vs
可以看出失败的用例执行了5次

import pytest

class Test_A():

    @pytest.mark.parametrize("a, b", [(1, 2), (3, 3), (5, 5)])
    def test_case01(self, a, b):
        print(f"测试用例1")
        assert a == b

超级详细的pytest测试和allure测试报告_第24张图片
pip install pytest-assume 多重校验
一个方法中写了多条断言,通常第一条过不去,下面的就不执行了,我们希望第一条报错之后,后面的也能够正常运行
使用pytest.assume(),代码如下:

import pytest

class Test_A():

    def test_case01(self):
        print(f"测试用例1")
        pytest.assume(1 > 2)
        pytest.assume(1 < 1)

pip intall pytest-html 测试报告

使用命令pytest -v -s --html=report.html --self-contained-html
超级详细的pytest测试和allure测试报告_第25张图片
浏览器打开
超级详细的pytest测试和allure测试报告_第26张图片

测试数据驱动:

也就是我们可以把数据写入到一个yaml文件中进行测试
新建一个data,yaml文件,内容如下
超级详细的pytest测试和allure测试报告_第27张图片
测试用例代码如下:

import yaml
import pytest

with open("./data.yaml") as f:
    datas = yaml.safe_load(f)
    myids = datas.keys()
    mydatas = datas.values()


class Test_A():

    @pytest.mark.parametrize("a, b", mydatas, ids=myids)
    def test_case_a(self, a, b):
        print("测试用例A")
        assert a > b

运行结果我们发现可以运行成功,如下
超级详细的pytest测试和allure测试报告_第28张图片

测试步骤驱动:

我们在进行自动化的时候需要定位元素,定位元素的时候我们会经常使用find_element方式,因此我们封装该方法到一个类里面,或者使之成为一个单独的方法,之后我们再进行元素定位的时候就可以调用这个方法进行元素定位,这个过程我们称之为测试步骤驱动,简单理解为我们basepage类里面封装的方法

pytest的高级用法

我们可以利用已有的hook函数来定义我们自己的插件,并把它放在conftest.py文件中作为自己的本地插件,实现我们想要的各种需求
hook函数地址:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html

场景一:
pytest_collection_modifyitems收集上来的测试用例实现定制化功能,解决的问题是:自定义用例的顺序,解决编码问题以及自动添加标签

我们在conftest.py文件里面添加如下内容:

from typing import List
import pytest

def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    print(items)
    items.reverse()

使用pytest -vs运行测试用例后:
超级详细的pytest测试和allure测试报告_第29张图片
对比之前的测试用例
超级详细的pytest测试和allure测试报告_第30张图片
我们使用数据化驱动的时候,yaml文件中如果含有中文,那么运行结果会显示乱码,也就是会显示这样:
超级详细的pytest测试和allure测试报告_第31张图片
为了正常能够显示中文,我们需要添加如下代码在conftest.py文件中
item.name = item.name.encode(‘utf-8’).decode(‘unicode-escape’)
item._nodeid = item.nodeid.encode(‘utf-8’).decode(‘unicode-escape’)
conftest.py代码:

from typing import List
import pytest

def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    print(items)
    # items.reverse()
    for item in items:
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')

data.yaml文件内容:

整数:
  - 12
  - 11
float:
  - 0.68
  - 0.6

test_a.py:

import pytest
import yaml
import pytest

with open("./data.yaml", encoding='utf-8') as f:
    datas = yaml.safe_load(f)
    print(datas)
    myids = datas.keys()
    mydatas = datas.values()


class Test_A():

    @pytest.mark.parametrize("a, b", mydatas, ids=myids)
    def test_case_a(self, a, b):
        print("测试用例A")
        print(datas)
        assert a > b

运行之后显示了正常了:
超级详细的pytest测试和allure测试报告_第32张图片
当然也可以自动添加标签,然后可以运行某个对应的标签的代码
修改conftest.py代码
if ‘case_a’ in item._nodeid:
item.add_marker(pytest.mark.case_a)
if ‘case_b’ in item._nodeid:
item.add_marker(pytest.mark.case_b)

from typing import List
import pytest

def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    print(items)
    # items.reverse()
    for item in items:
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')  #_nodeid测试用例名称
        if 'case_a' in item._nodeid:
            item.add_marker(pytest.mark.case_a)

        if 'case_b' in item._nodeid:
            item.add_marker(pytest.mark.case_b)

test_a.py文件还是这样

import pytest
import yaml
import pytest

with open("./data.yaml", encoding='utf-8') as f:
    datas = yaml.safe_load(f)
    print(datas)
    myids = datas.keys()
    mydatas = datas.values()


class Test_A():

    @pytest.mark.parametrize("a, b", mydatas, ids=myids)
    def test_case_a(self, a, b):
        print("测试用例A")
        assert a > b

    def test_case_b(self):
        print(f"测试用例B")
        assert 9 > 7

使用命令pytest test_a.py -m “case_b” -vs只运行case_b标签的测试用例
超级详细的pytest测试和allure测试报告_第33张图片
我们在运行测试用例的时候,也可以只运行我们上次运行失败的用例,使用参数
–lf, --last-failed 只重新运行上次运行失败的用例(或如果没有失败的话会全部跑)
–ff, --failed-first 运行所有测试,但首先运行上次运行失败的测试(这可能会重新测试,从而导致重复的fixture setup/teardown)

这里就不给大家举例子了

场景二:
我们可以使用pytest_addoption 自定义命令行参数,比如说我们需要在不同的环境中去运行我们的测试用例,那么我们就可以通过命令行去传递不同的环境标识,去得到我们想要的测试结果:

我们在conftest.py文件中编辑这些代码
def pytest_addoption(parser): #parser: 用户命令行参数与ini文件值的解析器
mygroup = parser.getgroup(“learn”) # group 将下面所有的 option都展示在这个group下。
mygroup.addoption("–env01", # 注册一个命令行选项
default=‘test’,
dest=‘env01’,
help=‘set your run env’
)
mygroup.addoption("–env02", # 注册一个命令行选项
default=‘test’,
dest=‘env02’,
help=‘set your run env’
)

#通过命令行来处理传递不同的参数,设置成fixture,将test环境和dev环境或者其他环境分别处理,获取想要的不同环境下的数据
@pytest.fixture(scope=‘session’)
def cmdoption(request):
myenv = request.config.getoption("–env", default=‘test’)
if myenv == ‘test’:
datapath = ‘datas/test/datas.yaml’

if myenv == 'dev':
    datapath = 'datas/dev/datas.yaml'

with open(datapath) as f:
    datas = yaml.safe_load(f)
return myenv,datas
from typing import List
import pytest
import yaml


def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    print(items)
    # items.reverse()
    for item in items:
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')  #_nodeid测试用例名称
        if 'case_a' in item._nodeid:
            item.add_marker(pytest.mark.case_a)

        if 'case_b' in item._nodeid:
            item.add_marker(pytest.mark.case_b)

def pytest_addoption(parser):   #parser: 用户命令行参数与ini文件值的解析器
    mygroup = parser.getgroup("learn")  # group 将下面所有的 option都展示在这个group下。
    mygroup.addoption("--env01",  # 注册一个命令行选项
                      default='test',
                      dest='env01',
                      help='set your run env'
                      )
    mygroup.addoption("--env02",  # 注册一个命令行选项
                      default='test',
                      dest='env02',
                      help='set your run env'
                      )

#通过命令行来处理传递不同的参数,设置成fixture,将test环境和dev环境或者其他环境分别处理,获取想要的不同环境下的数据
@pytest.fixture(scope='session')
def cmdoption(request):
    myenv = request.config.getoption("--env", default='test')
    if myenv == 'test':
        datapath = 'datas/test/datas.yaml'

    if myenv == 'dev':
        datapath = 'datas/dev/datas.yaml'

    with open(datapath) as f:
        datas = yaml.safe_load(f)
    return myenv,datas

设置文件datas/test/datas.yaml内容如下:

test:
  ip: 192.168.21.20
  port: 3306

设置文件datas/dev/datas.yaml内容如下:

dev:
  ip: 10.20.2.1
  port: 3309

新建一个测试用例test_addoption.py:

def test_addoption(cmdoption):
    env, datas = cmdoption
    print(f"{env},{datas}")
    print(type(datas))
    ip = datas[env]['ip']
    print(ip)
    port = datas[env]['port']
    url = "http://"+str(ip)+":"+str(port)
    print(url)

我们使用pytest --help会发现在帮助文档中有我们自己设置的环境参数
超级详细的pytest测试和allure测试报告_第34张图片
之后我们使用命令pytest test_addoption.py --env02 test -vs运行该测试用例,发现能够正常运行
超级详细的pytest测试和allure测试报告_第35张图片
场景三:参数化简化
pytest_generate_tests可以实现自定义动态参数化方案或者扩展,也就是我们重写这个hook函数即可,说白了,只要我们用到了参数化,都可以考虑这个功能是否能够给我们带来一些方便

在conftest.py里面最后添加如下内容
def pytest_generate_tests(metafunc: “Metafunc”) -> None:
if “param” in metafunc.fixturenames:
metafunc.parametrize(“param”, metafunc.module.data_params, ids=metafunc.module.dataids, scope=‘function’)

from typing import List
import pytest
import yaml


def pytest_collection_modifyitems(
    session: "Session", config: "Config", items: List["Item"]
) -> None:
    print(items)
    # items.reverse()
    for item in items:
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')  #_nodeid测试用例名称
        if 'case_a' in item._nodeid:
            item.add_marker(pytest.mark.case_a)

        if 'case_b' in item._nodeid:
            item.add_marker(pytest.mark.case_b)

def pytest_addoption(parser):   #parser: 用户命令行参数与ini文件值的解析器
    mygroup = parser.getgroup("learn")  # group 将下面所有的 option都展示在这个group下。
    mygroup.addoption("--env01",  # 注册一个命令行选项
                      default='test',
                      dest='env01',
                      help='set your run env'
                      )
    mygroup.addoption("--env02",  # 注册一个命令行选项
                      default='test',
                      dest='env02',
                      help='set your run env'
                      )

#通过命令行来处理传递不同的参数,设置成fixture,将test环境和dev环境或者其他环境分别处理,获取想要的不同环境下的数据
@pytest.fixture(scope='session')
def cmdoption(request):
    myenv = request.config.getoption("--env", default='test')
    if myenv == 'test':
        datapath = 'datas/test/datas.yaml'

    if myenv == 'dev':
        datapath = 'datas/dev/datas.yaml'

    with open(datapath) as f:
        datas = yaml.safe_load(f)
    return myenv,datas

#
def pytest_generate_tests(metafunc: "Metafunc") -> None:
    if "param" in metafunc.fixturenames:
        metafunc.parametrize("param", metafunc.module.data_params, ids=metafunc.module.dataids, scope='function')

新建一个test_param.py文件,内容如下

import yaml

with open("./data_params.yaml") as f:
    data = yaml.safe_load(f)
    data_params = data.values()
    dataids = data.keys()


def test_param(param):
    print(f"{param}")

新建一个./data_params.yaml文件,内容如下:

test1: [1, 2, 3]
test2: [4, 5, 6]
test3: [7, 8, 9]

我们运行这个test_param.py文件
超级详细的pytest测试和allure测试报告_第36张图片
这里我们需要注意的是:
测试用例里面的参数名要和conftest.py文件中pytest_generate_tests方法中的param名字要一致,可以自定义这个名字,前后一致即可
conftest.py文件中pytest_generate_tests方法中的data_params和dataids要和测试用例中的data_params和dataids也要一致,就像我们这个例子中的conftest.py和test_param.py这两个文件一致即可

6、allure测试报告:

allure是一个轻量级灵活的支持多语言的测试报告工具,java语言开发,支持pytest, javascript, php, ruby等,也可以集成到jenkins,在pycharm中我们需要安装allure-pytest(或者pip install allure-pytest)
在测试执行期间收集结果
pytest [测试文件] -s -q --alluredir=./resullt/(–alluredir这个选项用于指定存储测试结果的路径)
查看报告
allure serve ./result/
常用的特性
@feature添加功能名称
@story添加子功能名称
@step添加步骤细节
@attach天机具体的文本信息(图片、视频、网页等)

import allure

@allure.feature("加购模块")
class TestA():

    @allure.story("第一条用例")
    def test_case1(self):
        print("测试用例1")

    @allure.story("第二条用例")
    def test_case2(self):
        print("测试用例2")

    @allure.story("第三条用例")
    def test_case3(self):
        print("测试用例3")

    @allure.story("第四条用例")
    def test_case4(self):
        print("测试用例4")

@allure.feature("结算模块")
class TestB():

    @allure.story("结算模块第一条用例")
    def test_case1(self):
        print("结算模块测试用例1")

    @allure.story("结算模块第二条用例")
    def test_case2(self):
        print("结算模块测试用例2")

只执行结算模块的测试用例
pytest test_a.py --allure-features=“结算模块” -vs
超级详细的pytest测试和allure测试报告_第37张图片
只执行结算模块第二条用例
pytest test_a.py --allure-stories=“结算模块第二条用例” -vs

超级详细的pytest测试和allure测试报告_第38张图片
我们在源代码里面添加测试步骤:

import allure

@allure.feature("加购模块")
class TestA():

    @allure.story("第一条用例")
    def test_case1(self):
        with allure.step("步骤一:选择商品"):
            print("选择商品")

        with allure.step("步骤二:点击加入购物车"):
            print("点击加入购物车")
        print("测试用例1")

    @allure.story("第二条用例")
    def test_case2(self):
        print("测试用例2")

    @allure.story("第三条用例")
    def test_case3(self):
        print("测试用例3")

    @allure.story("第四条用例")
    def test_case4(self):
        print("测试用例4")

@allure.feature("结算模块")
class TestB():

    @allure.story("结算模块第一条用例")
    def test_case1(self):
        print("结算模块测试用例1")

    @allure.story("结算模块第二条用例")
    def test_case2(self):
        print("结算模块测试用例2")

只运行架构模块
pytest test_a.py --allure-features=“加购模块” -vs

超级详细的pytest测试和allure测试报告_第39张图片
执行生成一个测试结果
pytest test_a.py --allure-features=“加购模块” -vs --alluredir=./result
这里记录了我们每一条测试用例的执行结果
超级详细的pytest测试和allure测试报告_第40张图片
使用allure serve ./result命令生成测试报告
超级详细的pytest测试和allure测试报告_第41张图片
超级详细的pytest测试和allure测试报告_第42张图片
在测试报告中加入一个测试用例的链接地址,这里我们使用https://www.baidu.com/为例
修改源码如下
test_link = “https://www.baidu.com/”
@allure.testcase(test_link, “加购模块第二条测试用例”)

import allure

@allure.feature("加购模块")
class TestA():

    @allure.story("第一条用例")
    def test_case1(self):
        with allure.step("步骤一:选择商品"):
            print("选择商品")

        with allure.step("步骤二:点击加入购物车"):
            print("点击加入购物车")
        print("测试用例1")
    test_link = "https://www.baidu.com/"
    @allure.testcase(test_link, "加购模块第二条测试用例")
    def test_case2(self):
        print("测试用例2")

    @allure.story("第三条用例")
    def test_case3(self):
        print("测试用例3")

    @allure.story("第四条用例")
    def test_case4(self):
        print("测试用例4")

运行如下:
pytest test_a.py --allure-features=“加购模块” -vs --alluredir=./result1
allure serve ./result1

超级详细的pytest测试和allure测试报告_第43张图片
使用allure serve ./result1是直接唤起浏览器,生成一个测试报告,如果我们要在本地直接生成一个html文件呢,我们可以使用
allure generate ./result1
在这里插入图片描述
本地会生成一个allure-report文件
超级详细的pytest测试和allure测试报告_第44张图片
右键打开index.html,这个是我们想要的生成的测试报告文件
超级详细的pytest测试和allure测试报告_第45张图片
我们指定生成一个哪一个文件下面,假设我们指定生成report文件里面,使用命令
allure generate ./result1 -o report
在这里插入图片描述
超级详细的pytest测试和allure测试报告_第46张图片

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

级别:Trivial-不重要 Minor不太重要 Normal 正常问题 Critical严重 Blocker:阻塞
在方法函数和类上面加@allure.severity(allure.severity_level.TRIVIAL)
执行时 pytest -s -v 文件名 --allure-severities="normal,critical"

import allure
#@allure.feature("加购模块")
class TestA():

    @allure.severity(allure.severity_level.CRITICAL)
    def test_case1(self):
        with allure.step("步骤一:选择商品"):
            print("选择商品")

        with allure.step("步骤二:点击加入购物车"):
            print("点击加入购物车")
        print("测试用例1")

    @allure.severity(allure.severity_level.MINOR)
    def test_case2(self):
        print("测试用例2")

    @allure.severity(allure.severity_level.NORMAL)
    def test_case3(self):
        print("测试用例3")

    @allure.severity(allure.severity_level.BLOCKER)
    def test_case4(self):
        print("测试用例4")

执行结果:
超级详细的pytest测试和allure测试报告_第47张图片

我们希望不适用方法名命名我们的测试报告的标题,也就是如图所示的位置

超级详细的pytest测试和allure测试报告_第48张图片
修改代码如下@allure.title(“加购第一条用例”):

import allure
#@allure.feature("加购模块")
class TestA():

    @allure.title("加购第一条用例")
    def test_case1(self):
        with allure.step("步骤一:选择商品"):
            print("选择商品")

        with allure.step("步骤二:点击加入购物车"):
            print("点击加入购物车")
        print("测试用例1")

    @allure.severity(allure.severity_level.MINOR)
    def test_case2(self):
        print("测试用例2")

    @allure.severity(allure.severity_level.NORMAL)
    def test_case3(self):
        print("测试用例3")

    @allure.severity(allure.severity_level.BLOCKER)
    def test_case4(self):
        print("测试用例4")

使用pytest test_a.py --alluredir=./result3
生成测试结果
超级详细的pytest测试和allure测试报告_第49张图片
使用allure serve ./result3生成测试报告
超级详细的pytest测试和allure测试报告_第50张图片
添加文本,html代码块,截图和视频
代码修改如下

import allure
#@allure.feature("加购模块")
class TestA():

    @allure.title("加购第一条用例")
    def test_case1(self):
        allure.attach("这是一个纯文本", attachment_type=allure.attachment_type.TEXT)

    def test_case2(self):
        print("测试用例2")
        allure.attach("这是一段htmlbody代码块", "html网页", attachment_type=allure.attachment_type.HTML)

    def test_case3(self):
        print("测试用例3")
        allure.attach.file("E:\hewangtong\picture\\300-220.jpg", name = "这是图片", attachment_type=allure.attachment_type.JPG)

    def test_case4(self):
        print("测试用例4")
        allure.attach.file("E:\hewangtong\VIDEO\\《更完善的中后台微前端解决方案-qiankun》.mp4", name = "这是一个视频", attachment_type=allure.attachment_type.MP4)

使用pytest test_a.py --alluredir=./result4命令生成测试结果
超级详细的pytest测试和allure测试报告_第51张图片
使用allure serve ./result4命令生成测试报告
超级详细的pytest测试和allure测试报告_第52张图片
我们也可以本地起一个服务,方便其他同学访问到我们的测试报告
allure open -h 127.0.0.1 -p 8880 ./report/
超级详细的pytest测试和allure测试报告_第53张图片
浏览器里面输入地址http://127.0.0.1:8880/index.html即可访问对应的测试报告
超级详细的pytest测试和allure测试报告_第54张图片
小插曲:我们可以使用hamcrest进行断言范围,官网地址:http://hamcrest.org/,里面有各种语言的源代码链接,大家可以按需取用

你可能感兴趣的:(python,allure,pytest,软件测试)