请求Fixture

fixture是pytest中非常重要的功能,大部分项目都可能会用到fixture。

pytest-yaml-sanmu 可以借助pytest的内置标记 usefixtures 可以帮助用例自动的使用fixture。

创建fixture

pytest中的fixtures大致有两个用途

  1. 在用例执行之前、执行之后,自动的执行

  2. 通过fixture为用例提供数据

@pytest.fixture()
def print_msg():
    print('用例开始执行') #  yeild 之前为前置
    yield

    print('用例执行结束')#  yeild 之后为前置


@pytest.fixture
def base_url():
    yield 'https://www.baidu.com' #  yeild 指定返回值

当然了,也可以同时实现两种用途:

@pytest.fixture
def base_url():
    print('用例开始执行') #  yeild 之前为前置
    yield 'https://www.baidu.com' #  yeild 指定返回值
    print('用例执行结束')#  yeild 之后为前置

请求fixture

用例如果需要使用fixture,可以通过标记 usefixtures 来进行请求。

注意标记名是 s 结尾,表明允许同时请求多个fixture:

# test_mark_usefixtures.yaml

name: 请求fixture
mark:
  - usefixtures:
      - print_msg
      - base_url
steps:
  - request:
      method: get
      url: http://baidu.com

执行结果如下:

(.venv) C:\demo\pytest-yaml-demo>pytest -vs
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.3.4, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: yaml-1.1.0
collected 1 item

tests/usefixtures/test_mark_usefixtures.yaml::请求fixture 用例开始执行
http://baidu.com
PASSED用例执行结束


============================== 1 passed in 0.02s ===============================

使用fixture返回值

在fixture的第二个用途中,会为用例提供数据。

那么用例该如何获取和使用这个数据呢?一共有两种方式

第一种方式,

如果该数据是字符串或数字,可以直接写入yaml中使用的,可采用【参数变量】的方式进行使用

# test_mark_usefixtures_values.yaml

name: fixture返回值
mark:
  - usefixtures:
      - print_msg
      - base_url
steps:
  - request:
      method: get
      url: ${base_url}/abc.html

执行结果如下:

(.venv) C:\demo\pytest-yaml-demo>pytest -vs
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.3.4, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: yaml-1.1.0
collected 1 item

tests/usefixtures/test_mark_usefixtures_values.yaml::fixture返回值 用例开始执行
https://www.baidu.com/abc.html
PASSED用例执行结束


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

由结果可知,用例使用了fixture的返回值来决定服务器地址。


第二种方式,

如果fixture返回值是一个对象,不能直接作为yaml内容,可在hook中更灵活的使用

首先创建fixture:

@pytest.fixture()
def driver():
    obj = APIClient
    yield obj

接着在yaml中请求fixture:

name: 在hook中使用fixture
mark:
  - usefixtures:
      - client
steps:
  - request:
      method: get
      url: /abc.html

最后在hook中指定fixture返回值使用方式:

def pytest_yaml_run_step(item):
    step = item.current_step
    request = step.get('request')

    fixture_client = item.usefixtures.get('client') # 获取usefixtures中的fixture

    if fixture_client:
        fixture_client.request(**request) # 使用fixture发送请求
        return

第二种方法为用例的执行方式提供更多的灵活和扩展性,适合对pytest比较熟悉之后使用。

参数化fixture

pytest的fixture也可以参数化,其效果和 mark.parametrize 相似,都会生成更多的用例来执行。

唯一的区别是:

  • mark.parametrize 的参数值由用例提供,写在yaml中

  • fixture参数化的参数值由fixture提供,写在python中

下面是一个参数化的fixture

@pytest.fixture(params=['a', 'b', 'c'])
def name(request):
    return request.param

其返回值不是固定的,而是依次将 abc 作为返回值, 这使得请求该fixture的用例也会执行3次。

# test_mark_usefixtures_params.yaml

name: fixture返回值
mark:
  - usefixtures:
      - name
steps:
  - request:
      method: get
      url: https://www.baidu.com/?o=${name}

执行结果如下:

(.venv) C:\demo\pytest-yaml-demo>pytest -vs
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.3.4, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: yaml-1.1.0
collected 3 items

tests/usefixtures/test_mark_usefixtures_params.yaml::fixture返回值[a] https://www.baidu.com/?o=a
PASSED
tests/usefixtures/test_mark_usefixtures_params.yaml::fixture返回值[b] https://www.baidu.com/?o=b
PASSED
tests/usefixtures/test_mark_usefixtures_params.yaml::fixture返回值[c] https://www.baidu.com/?o=c
PASSED

============================== 3 passed in 0.02s ===============================

经过yaml用例是通过 mark 的方式使用 fixture ,但是在能力、效果上与python用例无异。