超详细从入门到精通,pytest自动化测试框架实战-fixture多样玩法(九)


前言

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

代码版的测试用例也不例外。

pytest自动化测试框架:https://www.bilibili.com/video/BV18K411m7FH/

在自动化测试框架当中,我们也需要编写:
用例执行之前的环境准备工作代码(前置工作代码)
用例执行之后的环境清理工作(后置工作代码)

通常,在自动化测试框架当中,都叫做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

2、测试类级别:一个测试类只执行一次前置和后置。
前置函数名称:setup_class
后置函数名称:teardown_class
注意:用@classmethod装饰

3、测试模块级别:一个测试模块只执行一次前置和后置。
前置函数名称: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("xxxxxx")
        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
fixture通过函数实现;
使用@pytest.fixture进行装饰;

import pytest

@pytest.fixture
def init():
    pass

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

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

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

import pytest


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

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

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

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("用例执行之后,执行的代码")  # 只有用例执行之后的后置清理代

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定义好之后,可以明确:

fixture处理了哪些前置准备工作、哪些后置清理工作
fixture作用在哪个范围 (是测试函数?还是测试类?还是测试会话?还是测试模块?)
在以上2点都定下来了之后,接下来就是,在测试用例当中,根据需要调用不同的fixture。

调用方法有2种:

在测试用例/测试类上面加上:@pytest.mark.usefixture(“fixture的函数名字”);
将fixture函数名,作为测试用例函数的参数;

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

第一种方式案例如下:

请添加图片描述

第二种方式案例如下:

请添加图片描述

3、conftest.py共享机制

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

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

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

conftest.py共享实现

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

请添加图片描述

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级作用域。

请添加图片描述

请添加图片描述

下面是我整理的2023年最全的软件测试工程师学习知识架构体系图

一、Python编程入门到精通

请添加图片描述

二、接口自动化项目实战

请添加图片描述

三、Web自动化项目实战

请添加图片描述

四、App自动化项目实战

请添加图片描述

五、一线大厂简历

请添加图片描述

六、测试开发DevOps体系

请添加图片描述

七、常用自动化测试工具

请添加图片描述

八、JMeter性能测试

请添加图片描述

九、总结(尾部小惊喜)

只要你有梦想,就不要放弃追求;只要你肯努力,就没有克服不了的困难。每一次坚持,都会让你变得更加强大;每一步奋斗,都会让你走向更美好的未来。

只要心怀梦想,勇往直前,即便曲折艰难,也不会停步。每一次挫折都是成长的礼物,每一次努力都是迎接成功的必经之路。让我们用汗水铸就辉煌!

勇敢的追求自己的梦想,不畏艰难险阻;努力拼搏,不屈不挠,才能够走向成功之路。只要我们有信念,有勇气,就可以突破困难,创造属于自己的辉煌!

猜你喜欢

转载自blog.csdn.net/m0_70102063/article/details/130087420