setup和teardown能实现在测试用例执行之前或之后做一些操作,但是这种是整个测试脚本全局生效的;
如果想实现某些用例执行之前进行登录,某些用例执行之前不需要进行登录,这种场景我们再使用setup和teardown就无法实现了,这时候我们就需要用到fixture功能了。
1、fixture函数
fixture(scope="function", params=None, autouse=False, ids=None, name=None)
参数说明:
1)scope:fixture函数的作用域;
可选值:function(默认)、class、module、session
function:作用于每个方法或函数,每个方法或函数都运行一次
class:作用于整个class类,每个class中的所有test只运行一次
module:作用于整个模块,每个module中的所有test只运行一次
session:作用于整个session,整个session只运行一次(慎用)
2)params:列表类型;
一个可选的参数列表;
它将会多次调用被fixture标记的方法和所有用到这个fixture的test测试用例;
默认为None;当前调用参数可以用 request.param 来获取。
3)autouse:如果为True,则为所有测试用例激活fixture,运行测试用例的时候会自动运行被fixture标记的方法;
如果为False,则需要显示指定来激活fixture,不会自动运行。
4)ids:id字符串列表,与params相对应,因此它们也是测试的一部分。如果没有提供ids,那么将会从params来自动生成。
5)name:fixture的名称。默认为被fixture装饰器标记的函数名。
2、fixture的使用
1)通过参数引用fixture函数
举例:
# file_name:test_fixture.py
import pytest
class Test_A:
@pytest.fixture()
def before(self):
print("\n--------before fixture has ran--------")
def test_a(self, before): # test_a方法以参数的形式传入了被fixture标记的函数,fixture的名称默认为被fixture标记的函数名
print('-------test_a has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
2)通过使用name参数来引用fixture函数
①name参数表示fixture的重命名;
②通常来说使用 fixture 的测试函数会将 fixture 的函数名作为参数传递,但是 pytest 也允许将fixture重命名。
举例1:
# file_name:test_fixture.py
import pytest
class Test_A:
@pytest.fixture(name="before_fixture_name")
def before(self):
print("\n--------before fixture has ran--------")
def test_a(self, before_fixture_name): # test_a方法以参数的形式传入了被fixture标记的函数,这里的fixture名称为:before_fixture_name,如果不设置name参数,则fixture的名称默认为被fixture标记的函数名
print('-------test_a has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
举例2:
为fixture函数重命名之后,不可以在使用fixture函数的函数名来调用,只能通过fixture函数重命名的新名字来调用。
3)通过@pytest.mark.usefixtures(‘fixture函数名’)函数的形式引用fixture函数
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture() # 被fixture标记的函数也可以应用在测试类的外部,使用@pytest.mark.usefixtures()装饰器来引用
def before():
print("\n--------before fixture has ran--------")
@pytest.mark.usefixtures("before") # 通过使用usefixtures()来引用fixture,此时usefixtures()函数的入参是fixture函数的函数名
class Test_A:
def test_a(self):
print('-------test_a has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
4)通过autouse=True设置默认执行fixture函数
①fixture函数的autouse参数默认等于False;
②fixture函数的autouse参数若为True,刚每个测试函数都会自动调用该fixture函数,而且无需传入fixture函数名。
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture(autouse=True) # 通过参数autouse=True来设置fixture默认运行
def before():
print("\n--------before fixture has ran--------")
class Test_A:
def test_a(self):
print('-------test_a has ran-------')
assert 1
def test_b(self):
print('-------test_b has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
5)fixture作用域设置成function
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture(scope="function", autouse=True) # 作用域设置成function,通过参数autouse=True来设置fixture默认运行
def before():
print("\n--------before fixture has ran--------")
class Test_A:
def test_a(self):
print('-------test_a has ran-------')
assert 1
def test_b(self):
print('-------test_b has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
6)fixture作用域设置成class
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture(scope="class", autouse=True) # 作用域设置成class,通过参数autouse=True来设置fixture默认运行
def before():
print("\n--------before fixture has ran--------")
class Test_A:
def test_a(self):
print('-------test_a has ran-------')
assert 1
def test_b(self):
print('-------test_b has ran-------')
assert 1
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
7)fixture的返回值使用
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture()
def return_data():
print("\n--------before fixture has ran--------")
return 2 # 返回值
class Test_A:
def test_a(self, return_data):
print('-------test_a has ran-------')
assert 1 == return_data # 拿到返回值做断言
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
8)fixture的params参数使用
①params形参是fixture函数的可选形参列表,支持列表传入;
②不传此参数时默认为None;
③每个param的值fixture函数都会去调用执行一次,类似for循环。
④可与参数ids一起使用,作为每个参数的标识,类似于用例参数化时的ids作用。
举例:
# file_name: test_fixture.py
import pytest
@pytest.fixture(params=[1, 2, 3])
def return_data(request): # 传入参数request,request系统内置的fixture
print("\n--------before fixture has ran--------")
return request.param # 通过request.param 获取当前传入的参数
class Test_A:
def test_a(self, return_data):
print('-------test_a has ran,return_data的值为:{}-------'.format(return_data))
assert 1 == return_data # 拿到返回值做断言
if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
运行结果:
从结果中我们可以看到测试用例执行了3次。通过设置params参数会导致多次调用被fixture标记的函数,并且使用该fixture函数的测试用例也会执行多次。
9)fixture的params参数于ids参数结合使用
①fixture函数未配置ids参数之前:用例执行后的标识为传入的params参数。
②fixture函数配置ids参数之后:用例执行后的标识为传入的ids参数。并与params参数一一对应。
10)fixture函数的相互调用(fixture函数与fixture函数之间的依赖关系)
举例1:
import pytest
# fixtrue作为参数,互相调用传入
@pytest.fixture()
def account():
a = "account"
print("第一层fixture")
return a
#Fixture的相互调用一定是要在测试类里调用这层fixture才会生次,普通函数单独调用是不生效的
@pytest.fixture()
def login(account):
print("第二层fixture")
class TestLogin:
def test_1(self, login):
print("直接使用第二层fixture,返回值为{}".format(login))
def test_2(self, account):
print("只调用account fixture,返回值为{}".format(account))
if __name__ == '__main__':
pytest.main()
举例2:
如果一个fixture函数依赖另外一个fixture函数,此时不能使@pytest.mark.usefixtures() 调用被依赖的fixture函数,这种调用方式不会生效。而是需要用函数传递的方式才能生效。
# test_fixture_02.py
import pytest
@pytest.fixture()
def login_weibo():
print("==============登陆微博===============")
@pytest.fixture()
# @pytest.mark.usefixtures("login_weibo") #这种方式不会生效
def get_weibo_data(login_weibo): # 这种方式才会生效
"""fixture函数依赖,需要用传递函数的方式"""
print("=============获取微博数据==============")
@pytest.mark.demo
class TestMyCode:
@pytest.mark.usefixtures("get_weibo_data")
def test_fixture_005(self):
"""fixture函数在测试脚本文件中"""
assert 1 == 1
运行结果:
注意:
①即使fixture函数之间支持相互调用,但普通函数直接使用fixture是不支持的,一定是在测试函数内调用才会逐级调用生效。
②有多层fixture函数调用时,最先执行的是最后一层fixture函数,而不是先执行传入测试函数的fixture函数。
③上层fixture函数的值不会自动return,这里就类似函数相互调用一样的逻辑。【函数调用值需要赋值给一个变量并使用】
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图 |
每个成功的背后都离不开艰苦的努力和坚持。要相信自己有能力实现自己的梦想,不管前方有多少艰难险阻,都不能阻挡你的步伐,直至抵达目的地。
每个人都有无尽的可能性,关键是要相信自己,勇往直前,不怕失败,不怕挫折,不断挑战自己,最终就能取得非凡的成功。
人生没有完美,只有不断的完善,勇敢地追求自己的梦想,不断探索未知的世界,积累知识和经验,最终才能成为一个真正强大的人。