玩转pytest—fixture

自动化测试框架中的 fixture

我们在编写测试用例,都会涉及到用例执行之前的环境准备工作,和用例执行之后的环境清理工作。

代码版的测试用例也不例外。在自动化测试框架当中,我们也需要编写:

用例执行之前的环境准备工作代码(前置工作代码)

用例执行之后的环境清理工作(后置工作代码)

通常,在自动化测试框架当中,都叫做 fixture。

pytest 作为 python 语言的测试框架,它的 fixture 有 2 种实现方式。

一种是 xunit-style,跟 unittest 框架的机制非常相似,即 setup/teardown 系列

一种是它自己的 fixture 机制,以@pytest.fixture 装饰器来申明。

pytest 的 fixture 实现方式一:xunit-style

pytest 的 xunit-style 有三个级别的 fixture:测试模块、测试类、测试函数。

  1. 测试函数/方法级别:每一个测试函数都会执行的前置和后置。
测试类内部的测试方法
前置函数名称:setup_method
后置函数名称:teardown_method
模块下的测试函数:
前置函数名称:setup_function
后置函数名称:teardown_function
  1. 测试类级别:一个测试类只执行一次前置和后置。
前置函数名称:setup_class
后置函数名称:teardown_class
注意:用@classmethod装饰
  1. 测试模块级别:一个测试模块只执行一次前置和后置。
前置函数名称:setup_module
后置函数名称:teardown_module

from selenium import webdriver
from time import sleep
from random import randint


def setup_module():
    print("====  模块级的 setup 操作  ====")


def teardown_module():
    print("====  模块级的 teardown 操作  ====")


def test_random():
    assert randint(1, 5) == 3


class TestWeb:

    @classmethod
    def setup_class(cls):
        print("====  测试类级的 setup 操作  ====")

    @classmethod
    def teardown_class(cls):
        print("====  测试类级的 teardown 操作  ====")

    def setup_method(self):
        print("====  测试用例级的 setup 操作  ====")
        self.driver = webdriver.Chrome()

    def teardown_method(self):
        print("====  测试用例级的 teardown 操作  ====")
        self.driver.quit()

    def test_search(self):
        self.driver.get("https://www.baidu.com/")
        self.driver.find_element_by_id("kw").send_keys("九九阜")
        self.driver.find_element_by_id("su").click()
        sleep(1)

pytest 也支持运行 unittest 的测试用例。支持 unittest 以下特性:

  • @unittest.skip
  • setUp/tearDown;
  • setUpClass/tearDownClass;
  • setUpModule/tearDownModule;

pytest 的 fixture 实现方式二:fixture 机制

通过@pytest.fixture 装饰器来定义 fixture。一个函数被@pytest.fixture 装饰,那么这个函数就是 fixture。

使用 fixture 时,分为二个部分:fixture 定义、fixture 调用。

除此之外,还有 fixture 的共享机制,嵌套调用机制。

1、定义 fixture。

1)fixture 通过函数实现。

2)使用@pytest.fixture 进行装饰

import pytest

@pytest.fixture
def init():
    pass

3)前置准备工作代码和后置清理工作代码,都写在一个函数里面。

4)通过 yeild 关键字,区分前置代码和后置代码 。yeild 之前的代码为前置代码,yeild 之后的代码为后置代码

在实际应用场景当中,可以只有前置准备工作代码,也可以只有后置清理工作代码。
import pytest


@pytest.fixture
def init():
    print("用例执行之前,执行的代码")  # 前置代码 
    yield 
    print("用例执行之后,执行的代码")  # 后置代码
 

@pytest.fixture
def init2():
    print("用例执行之前,执行的代码")  # 只有用例执行之前的前置准备代码
  

@pytest.fixture
def init3():
    yield
    print("用例执行之后,执行的代码")  # 只有用例执行之后的后置清理代码

5)fixture 有 4 个作用域:测试会话(session)、测试模块(module)、测试类(class)、测试用例(function)

测试会话:pytest 执行测试用例的整个过程,称为会话。

比如pytest收集到了100条用例并执行完成,这个过程称为测试会话。

设置 fixture 的作用域:通过@pytest.fixture(scope= 作用域)来设置。默认情况下,scope=function

import pytest


# 没有设置scope,默认为测试函数级别。即调用此fixture的测试类/模块/函数下,每个测试函数都会执行一次这个fixture
@pytest.fixture
def init():
    print("用例执行之前,执行的代码")  # 前置代码
    yield
    print("用例执行之后,执行的代码")  # 后置代码


# 设置scope为class。调用此fixture的测试类下,只执行一次这个fixture.
@pytest.fixture(scope="class")
def init2():
    print("用例执行之前,执行的代码")  # 只有用例执行之前的前置准备代码


# 设置scope为session。autouse表示自动使用。
# 那么在pytest收集用例后,开始执行用例之前会自动化执行这个fixture当中的前置代码,
# 当所有用例执行完成之后,自动化执行这个fixture的后置代码。
@pytest.fixture(scope="session",autouse=True)
def init3():
    yield
    print("用例执行之后,执行的代码")  # 只有用例执行之后的后置清理代码

6)fixture 的返回值设置:yeild 返回值

当测试用例当中,要使用 fixture 里生成的数据时,则需要 fixture 返回数据。

若有数据返回则:yeild 返回值

import pytest
from selenium import webdriver
from time import sleep


# 设置scope为class。调用此fixture的测试类下,只执行一次这个fixture.
@pytest.fixture(scope="class")
def init2():
    print("==== 测试类下,执行所有用例之前,执行的代码 ====")
    driver = webdriver.Chrome()
    yield driver   # 返回driver对象
    print("==== 测试类下,执行所有用例之后,执行的代码 ====")
    driver.quit()

2、调用 fixture

在 fixture 定义好之后,可以明确:

  1. fixture 处理了哪些前置准备工作、哪些后置清理工作
  2. fixture 作用在哪个范围(是测试函数?还是测试类?还是测试会话?还是测试模块?)

在以上 2 点都定下来了之后,接下来就是,在测试用例当中,根据需要调用不同的 fixture。

调用方法有 2 种:

1、在测试用例/测试类上面加上:@pytest.mark.usefixture("fixture 的函数名字")

2、将 fixture 函数名,作为测试用例函数的参数。

第2种用法,主要是用参数来接收fixture的返回值,以便在测试用例中使用。

第一种方式案例如下:

第二种方式案例如下:

 

3、conftest.py 共享机制

在某些大的业务场景下,很多用例当中,会使用相同的前置准备工作,和后置清理工作。

如果在每个测试模块下,都把前置准备工作,和后置清理工作写一遍,在维护上和优化上讲不够好。

pytest 框架提供了一个 fixture 共享的机制 ,可以让不同的用例模块,使用同一个 fixture。这就是 conftest.py 文件。

3.1 conftest.py 共享实现

  1. 在项目根目录下,创建一个 conftest.py 文件。
  2. 文件名必须是 conftest.py,大小写敏感,不可改名字。
  3. conftest.py 当中,可以编写多个 fixture
  4. 在测试用例文件当中,不需要引入 conftest.py 文件。直接调用 fixture 的函数名,会自动去 conftest.py 当中查找的。

3.2 conftest.py 层级作用域

conftest.py 在项目根目录下,则项目下的所有测试用例,均可使用 conftest.py 中定义的 fixture。即项目根目录下的 conftest.py,作用域是整个项目。

那,如果,conftest.py 当中的 fixture,只想在某个 python 包内可用呢?

conftest.py 实现了层级作用域。

简单来说就是:conftest.py 在哪个目录下,此目录下(包含子目录)的所有用例可使用其中的 fixture。

如下图:

根目录下的 conftest.py 里的 fixture,无论项目下的哪个用例,都可以使用。

子目录 moduleA 下的 conftest.py 里的 fixture,只有 moduleA 下的用例可以使用。

子目录 moduleB 下的 conftest.py 里的 fixture,只有 moduleB 下的用例可以使用。

 

moduleB 下的用例文件 test_module_b.py 中的用例,即可以使用根目录下的 conftest.py 中的 fixuture,又可以使用自己目录下的 conftest.py 的 fixture: 

 

那么有个问题,如果出现了同名 fixture 怎么办呢?

这里涉及到了,测试用例在执行时,调用 fixture 的顺序。一般来讲,按 就近原则 调用。

测试用例文件中的 fixture > 当前目录中的 fixture > 上级目录中的 fixture > 根目录中的 fixture

4、fixture 嵌套

fixture 不但支持共享 ,还支持嵌套使用。

嵌套使用即:一个 fixture,可以做另外一个 fixture 的参数。

如下图所示:名为 init2 的 fixture,可以作为 init 的参数。

并且,init 当中,将 init2 的返回值,同样返回。

 

当在用例当中,调用 init 时,init 会自动去调用 init2。

fixture 的执行顺序如下:

init2 的前置代码

init 的前置代码

init 的后置代码

init2 的后置代码

下图案例中,init2 为 class 级作用域,init 为 function 级作用域。

 

最后: 为了回馈铁杆粉丝们,我给大家整理了完整的软件测试视频学习教程,朋友们如果需要可以自行免费领取 【保证100%免费】

在这里插入图片描述

全套资料获取方式:点击下方小卡片自行领取即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值