fixture是pytest特有的功能,它用@pytest.fixture标识,定义在函数前面。在编写测试函数的时候,可以将此函数的名称作为传入参数,pytest会以依赖注入方式将该函数的返回值作为测试函数的传入参数。
fixture主要的目的是为了提供一种可靠和可重复性的手段去运行那些最基本的测试内容。例如在测试网站的功能时,每个测试用例都要登录和退出,利用fixture就可以只执行一次,否则每个测试用例都要执行这两步也是冗余。
应用:
登录登出功能
数据初始化
作用范围
fixture的scope有5个级别参数function(默认)、class、module、package和session。package被认为是实验性的。
·function:每个函数或方法都会调用;
·class:每个类调用一次,一个类可以有多种方法;
·module:每个.py文件调用一次,该文件内又有多个function和class;
·Session:多个文件调用一次,可以跨.py文件调用,每个.py文件就是module。
典型使用场景-登录登出
最典型的使用场景:登录功能,有些功能需要登录才能使用,例如支付功能和查看购物车,而浏览商品功能不需要登录。
fixture实现步骤如下:
(1)导入pytest。
(2)创建login()函数。
(3)在login()函数上加@pytest.fixture()。
(4)在要使用的测试方法中传入(登录函数名称),也就是先执行login()函数再执行本测试方法。
(5)不传入参数表明不需要登录,此时可以直接执行测试方法。
import pytest
@pytest.fixture()
def login():
print("用户名登录")
def test_cart(login):
print("登录后查看购物车")
def test_find_goods():
print("不登录浏览商品")
def test_pay(login):
print("登录后执行支付")
if __name__ == '__main__':
pytest.main(['-s','test.py'])
如图,在test_cart里,调用了login,因为查看购物车需要先登录。当测试用例执行时,会先执行login,将输出结果传给test_cart,然后执行test_cart.
典型使用场景-模块级别数据清理
测试方法后需要销毁并清除的数据该如何处理呢?可以用tesrdownClass,这里介绍用fixture方法。
通过在同一模块中加入yield关键字,当执行fixture时,第一次执行至yield,当整个模型的用例都执行结束后,继续执行fixture内的yield之后的语句。
步骤如下:(1)添加@pytest.fixture(scope=module)语句。
(2)在登录的方法中添加yield,之后添加销毁清除的步骤。
import pytest
@pytest.fixture(scope="module")
def open():
print("open broswer,open baidu")
yield
print("close broswer")#teardown
def test_cart():
print("登录后查看购物车")
def test_find_goods(open):
print("不登录浏览商品")
def test_pay():
print("登录后执行支付")
if __name__ == '__main__':
pytest.main(['-s','test.py'])
可以看到,第二个test里调用了fixture,在该test前执行了fixture,在最后执行fixture中yield之后的语句。
会话级别与conftest.py结合使用
fixture为session级别是可以跨.py模块调用的,也就是当有多个.py文件用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope="session"。既然已经是跨模块,需要在.py模块之上。因此采用一个单独的文件conftest.py,文件名称是固定的,pytest会自动识别该文件。放到工程的根目录下就可以全局调用了,如果放到某个package包下,那就只在该package内有效。
常用使用场景:当用户与其他测试工程师合作开发时,公共的模块要存放在不同文件中,要存放在大家都能访问的地方。通常是一些公用的配置。公共模块也可以,例如登录模块是大家公用的,因此应放在项目或包的路径下。
具体执行步骤如下:
(1)在本目录下创建conftest.py文件(文件名必须是这个)。
(2)将登录模块带@pytest.fixture写在conftest.py文件中。
import pytest
@pytest.fixture()
def login():
print("login with password")
在test文件中写入
import pytest
def test_cart(login):
print("登录后查看购物车")
def test_find_goods():
print("不登录浏览商品")
def test_pay(login):
print("登录后执行支付")
if __name__ == '__main__':
pytest.main(['-s','test.py'])
自动调用fixture
如果每次使用fixture都要通过传参的方式,则应改变原来测试方法的结构。如何不通过注入的方式让测试方法执行呢?有2种方式可选,第一种在fixture的参数中将autouse参数设置为True,这样便会自动应用所作用的范围。第二种使用@pytest.mark.usefixtures,在需要的测试方法上添加
方法一
在方法上面加@pytest.fixture(autouse=True),因为scope参数未设置,所以使用默认,其作用范围是function,也就是说每个测试方法都默认应用了。
方法二
在需要用到的地方使用
在测试方法上添加@pytest.mark.usefixtures("start")实现