Pytest - 自定义fixture

基础使用

任意py文件的方法中用@pytest.fixture 进行标记后使用


import pytest
# scope=functiOn 函数级别 - 手动调用
@pytest.fixture(scope='funciton')
def exec_sql():
    print("sql run.!!!!!!!")

class TestDemo1: 
    def test2(self, exec_sql):  # 将fixture 函数名称传入用例形参即为手动调用
        print("test1 run....")

if __name__ == '__main__':
    pytest.main(['-s'])

# out:
'''
============================= test session starts =============================
collecting ... collected 1 item

TestDemo.py::TestDemo1::test2 sql run.!!!!!!!
PASSED                                     [100%]test1 run....


============================== 1 passed in 0.01s ==============================
'''
# scope=function 函数级别 - 自动调用(参数 autouse默认是False )

import pytest

@pytest.fixture(scope='class', autouse=True)
def exec_sql():
    print("sql run.!!!!!!!")

class TestDemo1:

    def test2(self):
        print("test1 run....")

if __name__ == '__main__':
    pytest.main(['-s'])

# out:
'''
============================= test session starts =============================
collecting ... collected 1 item

TestDemo.py::TestDemo1::test2 sql run.!!!!!!!
PASSED                                     [100%]test1 run....


============================== 1 passed in 0.01s ==============================
'''


# 类级别 - 借助 yield 实现前后置
import pytest


@pytest.fixture(scope='class', autouse=True)
def exec_sql():
    print("sql run.!!!!!!!")
    yield
    print('close sql collection.!!!!!!!')

class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self):
        print("test2 run....")


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


#out:
'''
============================= test session starts =============================
collecting ... collected 2 items

TestDemo.py::TestDemo1::test1 sql run.!!!!!!!
PASSED                                     [ 50%]test1 run....

TestDemo.py::TestDemo1::test2 PASSED                                     [100%]test2 run....
close sql collection.!!!!!!!

============================== 2 passed in 0.01s ==============================
'''

测试用例中使用自定义fixture的返回值

import pytest


@pytest.fixture(scope='function')
def exec_sql():
    return "fixture 返回的值"

class TestDemo1:

    def test1(self,exec_sql):
        print("test1 run....")
        print(exec_sql)    # 打印调用fixture函数的返回值

    def test2(self,exec_sql):
        print("test2 run....")
        print(exec_sql)      # 打印调用fixture函数的返回值

if __name__ == '__main__':
    pytest.main()
# out:
'''
============================= test session starts =============================
collecting ... collected 2 items

test_demo2.py::TestDemo1::test1 PASSED                                   [ 50%]test1 run....
fixture 返回的值

test_demo2.py::TestDemo1::test2 PASSED                                   [100%]test2 run....
fixture 返回的值

============================== 2 passed in 0.01s ==============================
'''

类级别fixture 手动调用

使用 该方式在测试类上调用 @pytest.mark.usefixtures("")

import pytest


@pytest.fixture(scope='class',autouse=False)
def exec_sql():
    print("sql run.!!!!!!!")
    yield
    print('close sql collection.!!!!!!!')

@pytest.mark.usefixtures("exec_sql")
class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self):
        print("test2 run....")

class TestDemo3:
    def test1(self):
        print("TestDemo3 test1 run..")

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

# out:
'''
============================= test session starts =============================
collecting ... collected 3 items

test_demo3.py::TestDemo1::test1 sql run.!!!!!!!
PASSED                                   [ 33%]test1 run....

test_demo3.py::TestDemo1::test2 PASSED                                   [ 66%]test2 run....
close sql collection.!!!!!!!

test_demo3.py::TestDemo3::test1 PASSED                                   [100%]TestDemo3 test1 run..

============================== 3 passed in 0.01s ==============================

Process finished with exit code 0

'''

fixure 中获取params 传入的数据 实现数据驱动

import pytest



def read_data():
    '''数据源'''
    return ['xiaoming', 'zhangsan', 'wangwu']

@pytest.fixture(scope='function', autouse=False, params=read_data())
def exec_sql(request): 
    '''
    1.params
    2.requst: 参数固定写法,不能更改
    3.requst.param: 获得传入的参数
    '''
    print(request.param)
    print("sql run.!!!!!!!")
    yield
    print('close sql collection.!!!!!!!')


class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self, exec_sql):
        print("test2 run....")


class TestDemo3:
    def test1(self):
        print("TestDemo3 test1 run..")

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

# out(test2 执行了三次,因为exec_sql 产生了三个值): 
============================= test session starts =============================
collecting ... collected 5 items

test_demo4.py::TestDemo1::test1 PASSED                                   [ 20%]test1 run....

test_demo4.py::TestDemo1::test2[xiaoming] xiaoming
sql run.!!!!!!!
PASSED                         [ 40%]test2 run....
close sql collection.!!!!!!!

test_demo4.py::TestDemo1::test2[zhangsan] zhangsan
sql run.!!!!!!!
PASSED                         [ 60%]test2 run....
close sql collection.!!!!!!!

test_demo4.py::TestDemo1::test2[wangwu] wangwu
sql run.!!!!!!!
PASSED                           [ 80%]test2 run....
close sql collection.!!!!!!!

test_demo4.py::TestDemo3::test1 PASSED                                   [100%]TestDemo3 test1 run..

============================== 5 passed in 0.01s ==============================

测试用例中使用 fixture 返回的数据

import pytest

def read_data():
    return ['xiaoming', 'zhangsan', 'wangwu']

@pytest.fixture(scope='function', autouse=False, params=read_data())
def exec_sql(request): # requst 参数固定写法,不能更改
    print("sql run.!!!!!!!")
    yield request.param
    print('close sql collection.!!!!!!!')


class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self, exec_sql):
        ''' 使用fixture 返回的数据'''
        print("test2 run...." + exec_sql)


class TestDemo3:
    def test1(self):
        print("TestDemo3 test1 run..")


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

# out:
'''
============================= test session starts =============================
collecting ... collected 5 items

test_demo5.py::TestDemo1::test1 PASSED                                   [ 20%]test1 run....

test_demo5.py::TestDemo1::test2[xiaoming] sql run.!!!!!!!
PASSED                         [ 40%]test2 run....xiaoming
close sql collection.!!!!!!!

test_demo5.py::TestDemo1::test2[zhangsan] sql run.!!!!!!!
PASSED                         [ 60%]test2 run....zhangsan
close sql collection.!!!!!!!

test_demo5.py::TestDemo1::test2[wangwu] sql run.!!!!!!!
PASSED                           [ 80%]test2 run....wangwu
close sql collection.!!!!!!!

test_demo5.py::TestDemo3::test1 PASSED                                   [100%]TestDemo3 test1 run..


============================== 5 passed in 0.02s ==============================

Process finished with exit code 0
'''

ids 与params参数结合使用,给参数起别名

import pytest


def read_data():
    return ['xiaoming', 'zhangsan', 'wangwu']


@pytest.fixture(scope='function', autouse=False, params=read_data(), ids=['a', 'b', 'c'])
def exec_sql(request):  # requst 参数固定写法,不能更改
    print("sql run.!!!!!!!")
    yield request.param
    print('close sql collection.!!!!!!!')


class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self, exec_sql):
        print("test2 run...." + exec_sql)


class TestDemo3:
    def test1(self):
        print("TestDemo3 test1 run..")

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

name 参数 给fixture 起别名

需要注意的是一旦给fixture 起了别名后,原来被@pytest.fixture 标记过的方法名称就失效了

fixture 结合 conftest.py 文件使用

  • conftest.py 它是专门用于存放fixture的配置文件。名称是固定的,不能变
  • 在conftest.py 文件里面所有的方法在调用时都不需要导包
  • conftest.py 文件可以有多个,并且多个conftest.py 文件里面的多个fixture 可以被一个用例调用
  • 当用例调用多个fixture时,按方法传入的参数顺序调用

调用的优先级

  • fixture 全部是自动调用: fixture的优先级高于setup/teardown/setup_class/teardown_class
  • fixture 是手动调用: setup/teardown/setup_class/teardown_class 的优先级高于fixture

fixture 全部是自动调用

# conftest.py

import pytest

@pytest.fixture(scope="session", autouse=True)
def first():
    print("全局会话级别的fixture_前置")
    yield
    print("全局会话级别的fixture_后置")


@pytest.fixture(scope="class", autouse=True)
def second():
    print("fixture_class_前置")
    yield
    print("fixture_class_后置")


@pytest.fixture(scope="function", autouse=True)
def third():
    print("fixture_function_前置")
    yield
    print("fixture_function_后置")


# test_demo7.py
import pytest

class TestDemo1:

    def test1(self):
        print("test1 run....")

    def test2(self):
        print("test2 run....")

    def setup_class(self):
        print("setup_class")

    def teardown_class(self):
        print("teardown_class")

    def setup(self):
        print("setup")
    def teardown(self):
        print("teardown")


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

# 执行输出结果:
'''
test_demo7.py::TestDemo1::test1 全局会话级别的fixture_前置
fixture_class_前置
setup_class
fixture_function_前置
setup
PASSED                                   [ 50%]test1 run....
teardown
fixture_function_后置

test_demo7.py::TestDemo1::test2 fixture_function_前置
setup
PASSED                                   [100%]test2 run....
teardown
fixture_function_后置
teardown_class
fixture_class_后置
全局会话级别的fixture_后置
'''

类级别/方法级别 全部是手动调用

# conftest.py

import pytest


@pytest.fixture(scope="session", autouse=True)
def first():
    print("全局会话级别的fixture_前置")
    yield
    print("全局会话级别的fixture_后置")


@pytest.fixture(scope="class", autouse=False)
def second():
    print("fixture_class_前置")
    yield
    print("fixture_class_后置")


@pytest.fixture(scope="function", autouse=False)
def third():
    print("fixture_function_前置")
    yield
    print("fixture_function_后置")

# test_demo7.py

import pytest


@pytest.mark.usefixtures("second")
class TestDemo1:

    def test1(self, third):
        print("test1 run....")

    def test2(self, third):
        print("test2 run....")

    def setup_class(self):
        print("setup_class")

    def teardown_class(self):
        print("teardown_class")

    def setup(self):
        print("setup")

    def teardown(self):
        print("teardown")


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

# 输出:
test_demo7.py::TestDemo1::test1 全局会话级别的fixture_前置
setup_class
fixture_class_前置
setup
fixture_function_前置
PASSED                                   [ 50%]test1 run....
fixture_function_后置
teardown

test_demo7.py::TestDemo1::test2 setup
fixture_function_前置
PASSED                                   [100%]test2 run....
fixture_function_后置
teardown
fixture_class_后置
teardown_class
全局会话级别的fixture_后置

总结:pytest执行过程

  • 1.查询根目录下的conftest.py文件
  • 2.查询根目录下的pytest.ini文件,找到测试用例的位置
  • 3.查询测试用例目录下的conftest.py文件
  • 4.查询测试用例的py文件中是否有setup,teardown,setup_class,teardown_class
  • 5.再根据pytest.ini文件的测试用例规则去查找用例并执行

https://www.cnblogs.com/joker108/p/16795760.html
https://blog.csdn.net/weixin_43563447/article/details/115843308?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-115843308-blog-119120349.pc_relevant_3mothn_strategy_and_data_recovery&spm=1001.2101.3001.4242.2&utm_relevant_index=4

posted @ 2022-10-16 16:19  chuangzhou  阅读(73)  评论(0编辑  收藏  举报