python自动测试Pytest中Fixture装饰器

资讯 2年前 (2022) 千度导航
72 0 0

1、Fixture装饰器的用途

  1. 做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用Fixture来实现。
  2. 测试用例的前置条件可以使用Fixture实现,比直接使用Pytest框架的setup()和teardown()函数更加灵活。
  3. Fixture是Pytest用于将测试前后进行预备,清理工作的代码分离出核心测试逻辑的一种机制!
  4. Fixture可以实现Unittest不能实现的功能,比如:Unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是Fixture却可以解决这个问题。

2、Fixture参数说明

可以使用pytest.fixture()查看fixture()函数的源码和所需要的参数,同Fixture装饰器需要的参数一样。

fixture(scope="function", params=None, autouse=False, ids=None, name=None):  

说明:

  • scope:表示被@pytest.fixture()装饰器所标识方法的作用域。 作用域有四个级别,函数function(默认),类class,模块module,包package/session。 说明:function作用域包含函数和方法。
  • params:一个可选的参数列表,用于做Fixture的参数化。 可将数据提供给其他的Fixture,或者所有测试使用它 。
  • autouse:autouse=Ture则开启自动使用Fixture功能,也是调用Fixture函数一种方法。 Fixture装饰器会自动执行作用域范围内的所有用例的前后置。autouse默认值为Flase。
  • ids:一个字符串id的列表,即当使用params参数化时,给每一个值设置一个变量名。 如果没有提供ID,params将自动生成ID 。
  • name:表示给被@pytest.fixture()装饰器修饰的方法取一个别名,调用时可以使用别名调用。 默认为装饰器所装饰的函数名称。

3、Fixture装饰器简单应用

使用Fixture装饰器来实现部分用例的前后置。

比如:我们在测试一个操作流程时,有的测试用例需要登陆,有的测试用例执行不需要用户登陆。

如果要直接使用setup_function()前置函数来实现,该文件中的所有用例执行前都需要进行用户登陆。

如下示例:

import pytest

# 函数级,前置函数
def setup_function():
    print("用户登陆")

def test_add_cart():
    print("添加购物车--需要登录")


def test_add_address():
    print("添加收货地址--需要登录")


def test_browser_goods():
    print("浏览商品--不需要登录")


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

"""
执行结果:

用户登陆
添加购物车--需要登录
PASSED用户登陆
添加收货地址--需要登录
PASSED用户登陆
浏览商品--不需要登录
PASSED
"""

我们可以使用Fixture装饰器来实现部分用例的前后置,如下示例:

"""
1.学习目标
    掌握pytest  fixture定义
2.操作步骤
    1.在定义的函数前添加装饰器
        @pytest.fixture()
    2.编写函数
        @pytest.fixture()
        def 函数名():
            代码
    3.使用fixture
        在测试用例中,将上面定义的函数名称,当做参数传入到测试用例中即可
        def test_xx(函数名):
            用例步骤

"""
import pytest


# 步骤1
@pytest.fixture()
def login():  # 步骤3
    print("输入账号,密码,进行登录")


def test_add_cart(login):  # 步骤3
    print("添加购物车--需要登录")


def test_add_address(login):  # 步骤3
    print("添加收货地址--需要登录")


def test_browser_goods():
    print("浏览商品--不需要登录")


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

"""
执行结果:

输入账号,密码,进行登录
添加购物车--需要登录
PASSED输入账号,密码,进行登录
添加收货地址--需要登录
PASSED浏览商品--不需要登录
PASSED

只有添加购物车,添加收货地址的用例,执行了登陆操作
"""

提示:Fixture装饰器既可以实现部分用例的前后置,也可以是现实全部用例的前后置,所以比单独使用前置setup()函数和后置teardown()函数灵活多了。

4、yield执行后置函数

前面的示例,是在用例前加前置条件,相当于执行了setup()前置函数,既然有setup()前置函数那就会有teardown()后置函数,Fixture里面的teardown()后置函数用yield来唤醒。

示例:

import pytest


# 步骤1
@pytest.fixture()
def login():  # 步骤2
    print("打开APP")
    print("输入账号,密码,进行登录")
    yield  # 当用例执行完成后,执行yield后的代码
    print("关闭APP")


def test_add_cart(login):  # 步骤3
    print("添加购物车--需要登录")


def test_add_address(login):  # 步骤3
    print("添加收货地址--需要登录")


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

"""
执行结果:

打开APP
输入账号,密码,进行登录
添加购物车--需要登录
关闭APP
PASSED打开APP
输入账号,密码,进行登录
添加收货地址--需要登录
关闭APP
PASSED
"""

5、addfinalizer关键字

yield是当用例执行完之后,会执行yield后面的代码,但用例不能有return返回值。

addfinalizer实现功能跟yield一样,但是用例可以return参数,传给后面用例。

示例1:

import pytest


@pytest.fixture()
def login(request): # request是Pytest中的一个关键字,固定写法。
    # 步骤1:正常编写前置用例
    print("打开APP")
    print("输入账号,密码,进行登录")
    username = '小明'

    # 步骤3:定义用例执行后要执行的代码,封装到一个函数中
    def closeApp():	# 这个closeApp函数命是自定义的
        print("关闭APP")
        
    # 步骤4:执行上面封装的代码。
    # 通过request关键字,结束上面的函数。
    request.addfinalizer(closeApp)# 终结函数
	
    # 步骤2:返回参数给测试用例。
    # 返回参数可以是变量,对象,表达式,常量值。
    return username


def test_add_cart(login):  # 步骤3
    print("添加购物车--需要登录")
    # 这里需要注意: 如果要使用fixture方法返回的数据,
    # 就直接填写fixture方法名称。
    # 返回参数的名称和可以和fixture方法的名称相同。
    print(f"登陆者:{login}") 


def test_add_address(login):  # 步骤3
    print("添加收货地址--需要登录")
    print(f"登陆者:{login}")

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

"""
执行结果:

test_01.py::test_add_cart 打开APP
输入账号,密码,进行登录
添加购物车--需要登录
登陆者:小明
PASSED关闭APP

test_01.py::test_add_address 打开APP
输入账号,密码,进行登录
添加收货地址--需要登录
登陆者:小明
PASSED关闭APP
"""

示例2:

# 示例一个selenium自动化关闭开启关闭浏览器的操作。
import time
import pytest
from selenium import webdriver


@pytest.fixture()
def driver(request):  # request是Pytest中的一个关键字,固定写法。
    # 步骤1:创建浏览器驱动对象
    driver = webdriver.Firefox()

    # 步骤3:定义用例执行后要执行的代码,封装到一个函数中
    def end():  # 这个end函数命是自定义的
        driver.quit()

    # 步骤4:执行上面封装的代码。
    # 通过request关键字,结束上面的函数。
    request.addfinalizer(end)  # 终结函数

    # 步骤2:返回浏览器驱动对象,给测试用例
    # 返回参数可以是变量,对象,表达式,常量值。
    # 返回参数的名称和可以和fixture方法的名称相同。
    return driver


def test_baidu(driver):
    """打开百度"""
    driver.get("http://www.baidu.com")
    time.sleep(3)


def test_163(driver):
    """打开网易"""
    driver.get("http://www.163.com")
    time.sleep(3)


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

示例3:

使用yield也可以返回数据。(这种方式好神奇)

import pytest


@pytest.fixture()
def login(request):
    print("打开APP")
    print("输入账号,密码,进行登录")
    username = '小明'
    yield username
    print("关闭APP")


def test_add_cart(login):  # 步骤3
    print("添加购物车--需要登录")
    print(f"登陆者:{login}")


def test_add_address(login):  # 步骤3
    print("添加收货地址--需要登录")
    print(f"登陆者:{login}")


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

"""
执行结果:
test_01.py::test_add_cart 打开APP
输入账号,密码,进行登录
添加购物车--需要登录
登陆者:小明
PASSED关闭APP

test_01.py::test_add_address 打开APP
输入账号,密码,进行登录
添加收货地址--需要登录
登陆者:小明
PASSED关闭APP
"""

总结:return和yield都表示返回的意思,但是return的后面不能有代码,yield的后面可以接代码。

6、带返回值的Fixture

上面例子是带返回值并且还要实现teardown()后置函数的Fixture写法。

这里就是单纯的说明带返回值的Fixture。

我们可以选择让Fixture返回我们需要的东西,如果Fixture需要配置一些数据,读个文件,或者连接一个数据库,那么你可以让Fixture返回这些数据或资源。

示例:

"""
1.学习目标
    掌握带返回值的fixture
2.操作步骤
    2.1 编写带返回值fixture
    2.2 使用测试用例调用
3.需求
"""
import pytest


# 编写fixture
@pytest.fixture()
def data():
    print("准备好的测试数据")
    return 3 # 返回数据


def test_data(data):
    print("执行用例步骤")
    print(f"得到参数{data}")  # 可以使用在用例步骤中
    assert data == 3  # 使用在断言中

"""
执行结果:

test_01.py::test_data 准备好的测试数据
执行用例步骤
得到参数3
PASSED
"""

说明:Fixture装饰类中,也可以实现数据的准备。

7、Fixture实现参数化

Fixture修饰的函数可以通过添加params参数来实现参数化。(实际工作中,不常用此方式)

(1)params参数的使用

request代表Fixture的调用状态,request.param作为返回值供测试使用。

示例:

"""
1.学习目标
    掌握带参数化fixture编写
2.操作步骤
    @pytest.fixture(params=[列表格式数据])
    request是pytest中内置关键字

"""
import pytest

# 编写fixture,带参数
data = [666, 888, 1000]

# request会接收到params=data的参数
# 然后request.param(固定写法)每次传递一个参数
@pytest.fixture(params=data)
def need_data(request):
    return request.param


def test_data(need_data):
    print(f"测试数据:{need_data}")
    assert 666 == need_data

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

"""
test_01.py::test_data 测试数据:666
PASSED
test_01.py::test_data[888] 测试数据:888
FAILED
test_01.py::test_data[1000] 测试数据:1000
FAILED
"""

说明:上面的例子,通过assert简单判断下拿到的request.param值,有没有在原来的参数列表中。实际上就相当于遍历了一遍参数列表,们可以看到测试方法被调用了3次。

(2)进阶使用

参数是一个元组列表格式的数据。

"""
1.学习目标
    掌握带参数化fixture编写
2.操作步骤
    @pytest.fixture(params=[列表格式数据])
    request是pytest中内置关键字
3.需求
4.总结
    1.pytest fixture 主要是用来完成测试用例执行前后操作
        例如:测试前后对数据库连接/断开;打开/关闭浏览器APP
    2.fixture还可以用来准备测试数据
        带参数fixture
        有返回值fixture  (在实际工作中返回数据比较灵活,推荐使用)
    3.fixture中的参数
        scope: 确定fixture作用范围 默认function,class,module,session
        autouse:当值true时,相当于setup
        name: 对fixture重命名
"""
import pytest


# 编写fixture,带参数
@pytest.fixture(params=[("孙悟空", 666), ("猪八戒", 777), ("沙和尚", 888)])
def need_data(request):
    return request.param


def test_data(need_data):
    print(f"测试人物:{need_data[0]}")
    print(f"测试分数:{need_data[1]}")



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

"""
执行结果:

测试人物:孙悟空
测试分数:666
PASSED测试人物:猪八戒
测试分数:777
PASSED测试人物:沙和尚
测试分数:888
PASSED
"""

总结:params参数支持的格式。

  • 列表[]。
  • 元组()。
  • 元素列表[(),(),()]。
  • 字典列表[{},{},{}],提示:只能取{}整体。
  • 字典元祖({},{},{}),提示:只能取{}整体。

8、@pytest.mark.usefixtures()的使用

@pytest.mark.usefixtures("fixturename")装饰类也是一种调用Fixture的方式。

@pytest.mark.usefixtures("fixturename")装饰类可以装饰模块、类、函数、方法。

usefixtures与传fixture区别:

如果Fixture有返回值,则不能用@pytest.mark.usefixtures("fixturename")装饰器修饰用例。

如果Fixture没有返回值,用@pytest.mark.usefixtures("fixturename")装饰器和@pytest.fixture()装饰器作用一样。

示例:

import pytest


# 步骤1
@pytest.fixture()
def login():
    print("打开APP")
    print("输入账号,密码,进行登录")
    yield  # 当用例执行完成后,执行yield后的代码
    print("关闭APP")

# 方式一:
def test_add_cart(login):
    print("添加购物车--需要登录")


# 方式二:就是把fixture方法传入usefixtures装饰器中
@pytest.mark.usefixtures("login")
def test_add_address():  #
    print("添加收货地址--需要登录")


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

"""
执行结果:

test_01.py::test_add_cart 打开APP
输入账号,密码,进行登录
添加购物车--需要登录
PASSED关闭APP

test_01.py::test_add_address 打开APP
输入账号,密码,进行登录
添加收货地址--需要登录
PASSED关闭APP
"""
版权声明:千度导航 发表于 2022年3月14日 16:31。
转载请注明:python自动测试Pytest中Fixture装饰器 | 千度百科

相关文章