pytest测试框架--fixture的基本使用

1、fixture的含义

fixture的目的是提供一个测试的基线,在此基线基础上,可以更可靠的进行重复测试。

2、fixture的优势

Pytest的fixture相对于传统的xUnit的setup/teardown函数做了显著的改进:
(1)测试fixture有明确的名称,通过在函数/模块/类或者整个项目中激活来使用
(2)测试fixture是模块化的实现,使用fixture名即可触发特定的fixture,fixture可以在其他fixture中进行使用测试fixture不仅可以进行简单的单元测试,也可以进行复杂的功能测试。可以根据配置和组件的选项进行参数化定制测试,或者跨函数/类/模块或者整个测试过程进行测试。
(3)pytest依然支持经典的xUnit的样式,你可以根据自己的喜好混合两种样式。

3、fixture参数

  • scope
  • params
  • autouse
  • ids
  • name
def fixture(
    fixture_function: Optional[_FixtureFunction] = None,
    *,
    scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function",
    params: Optional[Iterable[object]] = None,
    autouse: bool = False,
    ids: Optional[
        Union[
            Iterable[Union[None, str, float, int, bool]],
            Callable[[Any], Optional[object]],
        ]
    ] = None,
    name: Optional[str] = None,
) -> Union[FixtureFunctionMarker, _FixtureFunction]:
    """Decorator to mark a fixture factory function.

    This decorator can be used, with or without parameters, to define a
    fixture function.

    The name of the fixture function can later be referenced to cause its
    invocation ahead of running tests: test modules or classes can use the
    ``pytest.mark.usefixtures(fixturename)`` marker.

    Test functions can directly use fixture names as input arguments in which
    case the fixture instance returned from the fixture function will be
    injected.

    Fixtures can provide their values to test functions using ``return`` or
    ``yield`` statements. When using ``yield`` the code block after the
    ``yield`` statement is executed as teardown code regardless of the test
    outcome, and must yield exactly once.

    :param scope:
        The scope for which this fixture is shared; one of ``"function"``
        (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``.

        This parameter may also be a callable which receives ``(fixture_name, config)``
        as parameters, and must return a ``str`` with one of the values mentioned above.

        See :ref:`dynamic scope` in the docs for more information.

    :param params:
        An optional list of parameters which will cause multiple invocations
        of the fixture function and all of the tests using it. The current
        parameter is available in ``request.param``.

    :param autouse:
        If True, the fixture func is activated for all tests that can see it.
        If False (the default), an explicit reference is needed to activate
        the fixture.

    :param ids:
        List of string ids each corresponding to the params so that they are
        part of the test id. If no ids are provided they will be generated
        automatically from the params.

    :param name:
        The name of the fixture. This defaults to the name of the decorated
        function. If a fixture is used in the same module in which it is
        defined, the function name of the fixture will be shadowed by the
        function arg that requests the fixture; one way to resolve this is to
        name the decorated function ``fixture_<fixturename>`` and then use
        ``@pytest.fixture(name='')``.
    """
    fixture_marker = FixtureFunctionMarker(
        scope=scope, params=params, autouse=autouse, ids=ids, name=name,
    )

    # Direct decoration.
    if fixture_function:
        return fixture_marker(fixture_function)

    return fixture_marker

4、实战一:fixture作为参数使用

测试函数可以通过接受一个已经命名的fixture对象来使用它们。对于每个参数名,如果fixture已经声明定义,会自动创建一个实例并传入该测试函数。fixture函数通过装饰器标志@pytest.fixture来注册。下面是一个简单的独立的测试模块,包含一个fixture及使用它的测试函数。

使用场景:

  • 用例1需要登录
  • 用例2不需要登录
  • 用例3需要登录

用法

在方法前面加@pytest.fixtrue()

实战

  • 单个fixture
import pytest

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

def test_case1(login):
    print("test_case1,需要登录")
    pass

def test_case2():
    print("test_case2,不用登录")
    pass

def test_case3(login):
    print("test_case3,需要登录")
    pass

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


pytest测试框架--fixture的基本使用_第1张图片

  • 多个fixture
import pytest

//名字可以作为参数
@pytest.fixture()
def login():
    print("这个是登录方法")
    return ('tom',"123")

@pytest.fixture()
def operate():
    print("登录后的操作")

def test_case1(login,operate):
    print(login)

def test_case2():
    print("test_case2,不用登录")

def test_case3(login):
    print(login)

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

pytest测试框架--fixture的基本使用_第2张图片

5、实战二:fixture的作用范围

测试函数可以通过接受一个已经命名的fixture对象来使用他们。对于每个参数名,如果fixture已声明定义,会自动创建一个实例并传入该测试函数。fixture函数通过装饰器标志@pytest.fixture来注册。下面是一个简单的独立的测试模块,包含一个fixture及使用它的测试函数
|

名称 范围 说明
function 函数级 每一个函数或方法都会调用
class 类级别 每个测试类只运行一次
module 模块级 每一个.py文件调用一次
package 包级 每一个python包只调用一次(暂不支持)
session 会话级 每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法

作用范围顺序:session》module》class》function

使用场景

整个模块有多条测试用例,需要在全部用例执行之前打开浏览器,全部执行之后去关闭浏览器,打开和关闭操作只执行一次。

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

@pytest.mark.usefixtures("open")
def test_search1():
    print("test_search1")
    
def test_search2(open):
    print("test_search2")

def test_search3(open):
    print("test_search3")

注解:return 与 yield的区别:
return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束。
yield: 带有yield的函数是一个迭代器,函数返回某个值时,会停留在某个位置,返回函数值后,会在前面停留的位置继续执行直到程序结束

6、实战三:fixture与conftest.py结合使用

在使用之前我们先来了解什么是conftest.py?
实现测试用例的过程中,当你发现需要使用来自多个文件的fixture函数的时候,可以将这些fixture函数放到conftest.py中。你不需要导入这些fixture函数,它会由pytest自动检索。
fixture函数的检索顺序是从测试类开始,然后测试的模块,然后就是conftest.py文件,最后是内置的插件和第三方插件。

使用场景

你与其他测试工程师合作一起开发时,公共的模块要在不同文件中,要在大家都访问到的地方(建议可以放在项目的根目录,因为找到conftest.py文件,先在同级目录找,如果同级目录找不到时,会向上级目录继续找,指导找到为止)
ps:conftest.py名称是固定,不能修改

实战

conftest.py的内容如下:

import pytest

#这个一定不要忘记写
@pytest.fixture(scope="session")
def login():
    # setup操作
    print("用户需要先完成登录操作")
    username = "hxc"
    name = "pytest书籍"
    # 相当于return,但是return不会执行后面的语句,yield是可以
    yield username,name
    # teardown操作
    print("完成登出操作")

test_conftestDemo.py的内容如下:

import pytest


def test_search(login):
    username,name = login
    print(f"用户名:{username},搜索商品:{name}")

def test_cart(login):
    print("添加购物车")

def test_order():
    print("下单pytest书籍")

def test_login(login):
    print("添加购物车之前先登录")

def test_get_product(connectDB):
    print("获取商品信息先连接数据库")

@pytest.fixture()
def connectDB():
    print("连接数据库")
    yield
    print("断开数据库")

pytest测试框架--fixture的基本使用_第3张图片

7、实战四:fixture参数化

测试过程中需要大量的测试数据,如果每一个测试用例都编写一条测试用例,用例将是非常庞大的。一般会使用将测试用例用到的数据一参数的形式传入待测试用例中,并为每条测试数据生成一个测试结果数据。

使用场景

测试离不开数据,为了数据灵活,一般数据都是通过参数传的

使用方法

在fixture方法上加装饰器@pytest.fixture(params=[1,2,3]),就会传入三个数据1,2,3,分别将这三个数据传入到用例当中。传入的数据需要使用一个固定的参数名request来接收。

import pytest

@pytest.fixture(params=["selenium", "appium"])
def login(request):
    print(f"用户名:{request.param}")
    return request.param

def test_demo1(login):
    print(f"demo1 case 数据为: {login}")

pytest测试框架--fixture的基本使用_第4张图片

import pytest


@pytest.fixture(params=[["selenium",123],["appium",123456]])
def login(request):
    print(f"用户名:{request.param}")
    return request.param

def test_demo1(login):
    print(f"demo1 case: 数据为: {login}")

pytest测试框架--fixture的基本使用_第5张图片

你可能感兴趣的:(Pytest测试框架,架构,python)