pytest学习05--之fixture


1、前言:

  前面一篇讲到用例加setup和teardown 可以实现在测试用例之前或之后加入一些操作,但是这种是脚本生效的。如果我想实现以下场景:用例1 要先登录,用例2不需要登录,用例3需要登录。 很显然这就无法用setup和teardown来实现了。 这就是本篇学习的目的:自定义测试用例的预置条件

2、什么是fixture????

  1) fixture 是在测试函数运行前后,由pytest 执行的外壳函数;fixture的本质就是函数。

  2)它的作用是将一些非核心的测试逻辑从测试函数中分离出来,以便于其他测试函数使用,同时保持这些边缘逻辑的一致性

  3)fixture中的代码可以进行定制,满足多变的测试需求,包括:定义传入测试中的数据集,配置测试前系统的初始状态,为批量测试提供数据源等

3、fixture的定义

通过一个例子来看一下fixture的定义:

  @pytest.fixture()装饰器用于声明函数是一个fixture。即 被装饰器修饰的函数就是一个fixture函数,fixture函数内部可以实现一些初始化的操作。

 4、Fixture的使用

调用fixture函数有三种方法:

  1)fixture函数名直接作为测试用例的实参进行传递

import pytest


# @pytest.fixture(scope="function", autouse=True)
# def login():
#     print("请输入账号、密码登录浏览器")

@pytest.fixture(scope="function")
def login():
    print("请输入账号、密码登录浏览器")


def test_s1(login): # 将fixture函数名作为实参传递到测试用例函数中
    print("用例1: 登录后 其他动作11111")


def test_s2():
    print("用例2,不需要登录,操作 2222")


def test_s3(login):
    print("用例3, 登录后其他操作33333")

 2)使用装饰器 @pytest.mark.usefixtures("fixture")修饰测试用例函数---括号内为fixture函数名称

import pytest


# @pytest.fixture(scope="function", autouse=True)
# def login():
#     print("请输入账号、密码登录浏览器")

@pytest.fixture(scope="function")
def login():
    print("请输入账号、密码登录浏览器")


def test_s1(login):
    print("用例1: 登录后 其他动作11111")

@pytest.mark.usefixtures('login') # 括号内为fixture函数名称
def test_s2():
    print("用例2,不需要登录,操作 2222")


def test_s3(login):
    print("用例3, 登录后其他操作33333")


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

  3)使用autouse 参数

    指定fixture的参数 autouse=True 这样每个测试用例函数 会自动调用fixtrue(这里其实不准确,因为还涉及到fixture的范围scope,autouse=True时 在设置的范围内都会被调用)

例子:

import pytest
# 当 autouse 为True的时候 每个测试用例函数会自动调用fixture,不需要传参调用,当autouse = Fals(默认)时,需要在测试用例函数中传参进行调用
@pytest.fixture(scope="function", autouse=True)
def login():
    print("请输入账号、密码登录浏览器")


def test_s1():
    print("用例1: 登录后 其他动作11111")


def test_s2():
    print("用例2,不需要登录,操作 2222")


def test_s3():
    print("用例3, 登录后其他操作33333")


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

  小结: 如果测试用例需要使用fixture中返回的参数,那么通过后面的这两种方法是无法使用返回的参数的,因为fixture中返回的数据默认存在fixture名字里,所以只能使用第一种方式才可以调用fixture种的返回值。

import pytest


# @pytest.fixture(scope="function", autouse=True)
# def login():
#     print("请输入账号、密码登录浏览器")

@pytest.fixture(scope="function")
def login():
    print("请输入账号、密码登录浏览器")
    return 'hahah'


def test_s1(login):
    print("用例1: 登录后 其他动作11111")
    print(login+' test_s1')

@pytest.mark.usefixtures('login')
def test_s2():
    print("用例2,不需要登录,操作 2222")


def test_s3(login):
    print("用例3, 登录后其他操作33333")


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

  运行结果:

 

5、Fixture的优势

1、fixture相对于setup 和 teardown 来说有以下几点优势:

--命名方式灵活,不局限于setup 和 teardown 这几个命名

--conftest.py 配置可以实现不同用例脚本之间的数据共享,不需要import 就能自动找到一些配置

--scope = "module" 可以实现多个.py跨文件共享前置

--scope = “sesseion”可以实现多个.py跨文件使用一个session来完成多个用例

fixture(scope="function", params=None, autouse=False, ids=None, name=None):
"""使用装饰器标记fixture的功能,可以使用此装饰器(带或不带参)来定义fixture功能。fixture功能的名称可以在以后使用,引用它会在测试之前调用它:test模块或者 可以使用pytest.mark.userfixtures(fixturename标记),测试功能可以直接使用fixture名称作为输入参数,在这种情况下,夹具实例从fixture返回功能将被注入"""
:arg scope: scope 有四个级别的参数:function 默认,class,module session
:arg params: 一个可选参数列表,它将导致多个参数调用fixture功能和所有测试 使用它
:arg autouse: 如果为True,则为所有测试激活fixture func 可以看到它。如果为False(默认值)则显式需要参考来激活fixture
:arg ids : 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分,如果没有提供ID,他们讲从params自动生成
:arg  name:fixture的名称。 这默认为装饰函数的名称。如果fixture在定义它的同一个模块中使用,夹具的功能名称 将被请求夹具的功能arg遮蔽;解决这个问题的一种方法是将装饰函数命名“fixture_ ”然后使用”@ pytest.fixture(name ='')

  Fixture 可以选择使用yield 语句为测试函数提供它们的值,而不是return。在这种情况下,yield语句之后的代码块 作为拆卸代码执行(即 类似teardown功能),而不管测试结果如何,fixture功能必须只产生一次。

6、fixture 函数存放的位置

  1)如果你希望fixture函数的作用域仅局限于某个测试文件,那么把它写在该测试文件中;

  2)如果希望fixture 被多个测试文件共享,可以在公共目录下创建一个conftest.py,将fixture放在其中。

7、Fixture的作用范围参数传入(scope = "function"):

1、实现场景:用例1 需要先登录,用例2不需要登录,用例3需要先登录import pytest

当 autouse 为True的时候 每个测试用例函数会自动调用fixture,不需要传参调用,当autouse = Fals(默认)时,需要在测试用例函数中传参进行调用
import pytest
# 当 autouse 为True的时候 每个测试用例函数会自动调用fixture,不需要传参调用,当autouse = Fals(默认)时,需要在测试用例函数中传参进行调用
@pytest.fixture(scope="function", autouse=True)
def login(): print("请输入账号、密码登录浏览器") def test_s1(): print("用例1: 登录后 其他动作11111") def test_s2(): print("用例2,不需要登录,操作 2222") def test_s3(): print("用例3, 登录后其他操作33333") if __name__ == '__main__': pytest.main(['-s', '-v'])

  运行结果如下:----从运行结果看 当autouse 设置为True时 每个测试用例函数都会自动执行fixture。

============================= test session starts =============================
collecting ... collected 3 items

test_fixture.py::test_s1 请输入账号、密码登录浏览器
PASSED                                          [ 33%]用例1: 登录后 其他动作11111

test_fixture.py::test_s2 请输入账号、密码登录浏览器
PASSED                                          [ 66%]用例2,不需要登录,操作 2222

test_fixture.py::test_s3 请输入账号、密码登录浏览器
PASSED                                          [100%]用例3, 登录后其他操作33333


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

Process finished with exit code 0

  ********************************下面看 当autouse 设置为False的场景(默认)这种场景 只有对测试用例函数进行传参fixture函数名 才生效,不传递不生效---------------

@pytest.fixture(scope="function")
def login():
    print("请输入账号、密码登录浏览器")


def test_s1(login):
    print("用例1: 登录后 其他动作11111")


def test_s2():
    print("用例2,不需要登录,操作 2222")


def test_s3(login):
    print("用例3, 登录后其他操作33333")


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

  运行结果如下图:----------从运行结果看 在传递fixture函数的 test_s1 和test_s3中执行了fixture预置功能,没有传递fixture函数名的test_s2没有执行

============================= test session starts =============================
collecting ... collected 3 items

test_fixture.py::test_s1 请输入账号、密码登录浏览器
PASSED                                          [ 33%]用例1: 登录后 其他动作11111

test_fixture.py::test_s2 PASSED                                          [ 66%]用例2,不需要登录,操作 2222

test_fixture.py::test_s3 请输入账号、密码登录浏览器
PASSED                                          [100%]用例3, 登录后其他操作33333


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

相关