您现在的位置是:网站首页> 编程资料编程资料

Pytest fixture及conftest相关详解_python_

2023-05-25 476人已围观

简介 Pytest fixture及conftest相关详解_python_

前言

fixture是在测试函数运行前后,由pytest执行的外壳函数。fixture中的代码可以定制,满足多变的测试需求,包括定义传入测试中的数据集、配置测试前系统的初始状态、为批量测试提供数据源等等。fixture是pytest的精髓所在,类似unittest中setup/teardown,但是比它们要强大、灵活很多,它的优势是可以跨文件共享。

一、Pytest fixture

1.pytest fixture几个关键特性

  • 有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活
  • 按模块化的方式实现,每个fixture都可以互相调用
  • fixture可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题
  • fixture的范围从简单的单元扩展到复杂的功能测试,允许根据配置和组件选项对fixture和测试用例进行参数化

2.Pytest fixture定义

  • 定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要用test_开头,跟用例区分开。用例才是test_开头的命名;
  • fixture装饰器里的scope有四个级别的参数:function(不写默认这个)、class、module、session;
  • fixture可以有返回值,如果没有return,默认会是None;用例调用fixture的返回值,就是直接把fixture的函数名称作为参数传入;
  • fixture可以返回一个元组、列表或字典;
  • 测试用例可传单个、多个fixture参数;
  • fixture与fixture间可相互调用;

3.Pytest fixture用法

1)用法一:作为参数使用

fixture的名字直接作为测试用例的参数,用例调用fixture的返回值,直接将fixture的函数名称当做变量名称;如果用例需要用到多个fixture的返回数据,fixture也可以返回一个元祖,list或字典,然后从里面取出对应数据。

① 将fixture函数作为参数传递给测试用例

@pytest.fixture() def login(): print("this is login fixture") user = "chen" pwd = 123456 return user, pwd def test_login(login): """将fixture修饰的login函数作为参数传递给本用例""" print(login) assert login[0] == "chen" assert login[1] == 123456 assert "chen" in str(login)

② 同一个用例中传入多个fixture函数

@pytest.fixture() def user(): user = "cris" return user @pytest.fixture() def pwd(): pwd = "123456" return pwd def test_trans_fixture(user, pwd): """同一条用例中传入多个fixture函数""" print(user, pwd) assert "cris" in str(user) assert pwd == "123456"

③ fixture函数之间的相互传递

@pytest.fixture() def user2(): user = "cris" return user @pytest.fixture() def login_info(user2): """fixture与fixture函数之间的相互传递""" pwd = "e10adc3949ba59abbe56e057f20f883e" return user2, pwd def test_assert_login_info(login_info): print(login_info) print(type(login_info)) assert login_info[0] == "cris" assert login_info[1] == "e10adc3949ba59abbe56e057f20f883e"

2)用法二:提供灵活的类似setup和teardown功能

Pytest的fixture另一个强大的功能就是在函数执行前后增加操作,类似setup和teardown操作,但是比setup和teardown的操作更加灵活;具体使用方式是同样定义一个函数,然后用装饰器标记为fixture,然后在此函数中使用一个yield语句,yield语句之前的就会在测试用例之前使用,yield之后的语句就会在测试用例执行完成之后再执行。

@pytest.fixture() def run_function(): print("run before function...") yield print("run after function...") def test_run_1(run_function): print("case 1") def test_run_2(): print("case 2") def test_run_3(run_function): print("case 3")

运行结果如下:

常见的应用场景:@pytest.fixture可以用在selenium中测试用例执行前后打开、关闭浏览器的操作:

@pytest.fixture() def fixture_driver(): driver = webdriver.Chrome() yield driver driver.quit() def test_baidu(fixture_driver): driver = fixture_driver driver.get("http://www.baidu.com") driver.find_element_by_id('kw').send_keys("python fixture") driver.find_element_by_id('su').click()

3)用法三:利用pytest.mark.usefixtures叠加调用多个fixture

如果一个方法或者一个class用例想要同时调用多个fixture,可以使用@pytest.mark.usefixtures()进行叠加。注意叠加顺序,先执行的放底层,后执行的放上层。

需注意:

  • ① 与直接传入fixture不同的是,@pytest.mark.usefixtures无法获取到被fixture装饰的函数的返回值;
  • ② @pytest.mark.usefixtures的使用场景是:被测试函数需要多个fixture做前后置工作时使用;
@pytest.fixture def func_1(): print("用例前置操作---1") yield print("用例后置操作---1") @pytest.fixture def func_2(): print("用例前置操作---2") yield print("用例后置操作---2") @pytest.fixture def func_3(): print("用例前置操作---3") yield print("用例后置操作---3") @pytest.mark.usefixtures("func_3") # 最后执行func_3 @pytest.mark.usefixtures("func_2") # 再执行func_1 @pytest.mark.usefixtures("func_1") # 先执行func_1 def test_func(): print("这是测试用例")

执行结果:

4)用法四:fixture自动使用autouse=True

当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了,autouse设置为True,自动调用fixture功能。所有用例都会生效,包括类中的测试用例和类以外的测试用例

@pytest.fixture(autouse=True, scope="function") def func_auto(): """autouse为True时,会作用于每一条用例""" print("\n---用例前置操作---") yield print("---用例后置操作---") # func_auto函数的autouse=True时,无论是否使用usefixtures引用func_auto,都会执行func_auto @pytest.mark.usefixtures("func_auto") def test_01(): print("case 1") def test_02(): print("case 2") class Test: def test_03(self): print("case 3")

执行结果:

4.Pytest fixture四种作用域

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

fixture里面有个scope参数可以控制fixture的作用范围:

  • function:每一个函数或方法都会调用
  • class:每一个类调用一次,一个类中可以有多个方法
  • module:每一个.py文件调用一次,该文件内又有多个function和class
  • session:多个文件调用一次,可以跨.py文件调用(通常这个级别会结合conftest.py文件使用)

1)function级别

function默认模式为@pytest.fixture() 函数级别,即scope="function",scope可以不写。每一个函数或方法都会调用,每个测试用例执行前都会执行一次function级别的fixture。

# @pytest.fixture(scope="function")等价于@pytest.fixture() @pytest.fixture(scope="function") def func_auto(): """用例级别fixture,作用域单个用例""" print("\n---function级别的用例前置操作---") yield print("---function级别的用例后置操作---") # test_01会引用func_auto函数,test_02没有用修饰器修饰,故不会引用 def test_func_auto_fixture_1(func_auto): print("func 1 print") def test_func_auto_fixture_2(): print("func 2 print")

2)class级别

fixture的scope值还可以是class,此时则fixture定义的动作就会在测试类class的所有用例之前和之后运行,需注意:测试类中只要有一个测试用例的参数中使用了class级别的fixture,则在整个测试类的所有测试用例都会调用fixture函数

① 用例类中的测试用例调用fixture

执行fixture定义的动作,以及此测试类的所有用例结束后同样要运行fixture指定的动作

@pytest.fixture(scope="class") def class_auto(): """类级别fixture,作用域整个类""" print("\n---class级别的用例前置操作---") yield print("---class级别的用例后置操作---") class TestClassAutoFixture: # class级别的fixture任意一个用例引用即可 def test_class_auto_fixture_1(self, class_auto): print("class 1 print") def test_class_auto_fixture_2(self): print("class 1 print")

测试类中的第1条测试用例引用了fixture修饰的函数,则整个测试类的所有测试用例都会执行fixture函数的前置操作,在所有用例执行完成后,都会执行fixture函数的后置操作。

② 用例类外的测试用例调用fixture

如果在类外的函数中去使用class级别的fixture,则此时在测试类外每个测试用例中,fixture跟function级别的fixture作用是一致的,即在类外的函数中引用了class级别的fixture,则在此函数之前和之后同样去执行fixture定义的对应的操作。

def test_class_auto_fixture(class_auto): print("class 1 print")

如下图所示,测试类外的函数引用了class级别的fixture,则它的作用会等同于function级别的fixture,

运行结果如下:

3)module级别

在Python中module即.py文件,当fixture定义为module时,则此fixture将在当前文件中起作用。这里需要特别说明的是,当fixture的scope定义为module时,只要当前文件中有一个测试用例使用了fixture,不管这个用例是在类外,还是在类中,都会在当前文件(模块)的所有测试用例执行之前去执行fixture定义的行为以及当前文件的所有用例结束之后同样去执行fixture定义的对应操作。

@pytest.fixture(scope="module") def module_auto(): """作用于整个py文件""" print("\n---module级别的用例前置操作---") yield print("---module级别的用例后置操作---") # 测试类外和测试类内的函数方法都调用了module级别的fixture,但整个py文件只会生效一次fixture。 def test_module_scope_out_cla
                
                

-六神源码网