pytest系列——fixture之yield关键字实现teardown用例后置操作
fixture之yield关键字实现teardown用例后置操作
前言
①pytest之fixture函数使用(pytest测试框架测试固件 文中讲到,fixture函数是通过scope参数来控制setup级别;
②既然有setup函数作为用例之前的操作,测试用例执行完成之后那肯定也有teardown操作。
③但是fixture的teardown操作并不是独立的函数,用yield关键字唤醒teardown操作。【依然存在于fixture方法中】
yield实现teardown后置操作
实例1
#使用yield关键字实现teardown_xxx的功能
import pytest
# 此时,login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能。
@pytest.fixture()
def login():
############# 以下的代码相当于setup部分 ###########
print('登录系统')
token = 'a1b23c'
yield token
############# 以下的代码相当于teardown部分 ###########
print('退出登录')
# 在测试函数里, 通过形参声明要使用的测试固件
def test1(login):
# login参数的值是测试固件函数的返回值
print('执行测试 test1: ', login)
print('测试1')
def test2(login):
print('执行测试 test2: ', login)
print('测试2')
# 通过python解释器执行需要以下代码
if __name__ == '__main__':
pytest.main(["-s", "test_yieldDemo.py"])
运行结果:
【注意】:return和yield两个关键字都可以返回值;
yield关键字返回值后,后面的代码还会继续运行;【由于实例1中fixture函数login需要返回token,而且还需要继续执行teardown后置操作:所以选择yield关键字所以后面代码还会继续运行】
return关键字返回值后,后面的代码不会继续运行;
实例2
import pytest
@pytest.fixture(scope="module")
def open():
print("打开浏览器,并且打开百度首页")
yield
print("执行teardown!")
print("最后关闭浏览器")
def test_s1(open):
print("用例1:搜索python-1")
def test_s2(open):
print("用例2:搜索python-2")
def test_s3(open):
print("用例3:搜索python-3")
if __name__ == "__main__":
pytest.main(["-s", "test_fixturemodule2.py"])
运行结果:
实例3
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
@pytest.fixture(scope="session")
def open():
# 会话前置操作setup
print("===打开浏览器open===")
yield
# 会话后置操作teardown
print("===关闭浏览器open===")
@pytest.fixture
def login(open):
# 方法级别前置操作setup
print("===登陆操作login===")
name = "===账号==="
pwd = "===密码==="
# 返回变量
yield name, pwd
# 方法级别后置操作teardown
print("===登录成功login===")
def test_case1(login):
print("===测试用例1===")
# 返回的是一个元组
print(login)
# 分别赋值给不同变量
name, pwd = login
print(name, pwd)
assert "账号" in name
assert "密码" in pwd
def test_case2(login):
print("===测试用例2===")
print(login)
运行结果:
yield遇到异常
1、如果其中一个用例在执行时出现异常,不影响yield后面的teardown执行,运行结果互不影响,并且全部用例执行完之后,yield唤起teardown操作。
# 新建一个文件test_f1.py
# coding:utf-8
import pytest
@pytest.fixture(scope="module")
def open():
print("打开浏览器,并且打开百度首页")
yield
print("执行teardown!")
print("最后关闭浏览器")
def test_s1(open):
print("用例1:搜索python-1")
# 如果第一个用例异常了,不影响其他的用例执行
raise NameError # 模拟异常
def test_s2(open):
print("用例2:搜索python-2")
def test_s3(open):
print("用例3:搜索python-3")
if __name__ == "__main__":
pytest.main(["-s", "test_f1.py"])
运行结果:
2、但是fixture函数如果在setup执行期间发生异常,那么pytest是不会去执行yield后面的teardown内容。
yield关键字+with上下文管理器的结合使用
yield
关键字 也可以配合 with
上下文管理器 语句使用。【使得代码更加精简】
示例:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
import smtplib
@pytest.fixture(scope="module")
def smtp_connection():
with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:
yield smtp_connection
request.addfinalizer()将定义的函数注册为终结函数
除了yield可以实现teardown,我们也可以通过 request.addfinalizer()
的方式去注册终结函数来实现 teardown
用例的后置操作。
示例:
addfinalizer
的用法跟 yield
是不同的, addfinalizer
需要你去注册一个或多个作为终结器使用的函数。
例如:增加一个函数 fin,并且注册成终结函数。
代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
@pytest.fixture(scope="module")
def test_addfinalizer(request):
# 前置操作setup
print("===打开浏览器===")
test = "test_addfinalizer"
def fin():
# 后置操作teardown
print("===关闭浏览器===")
request.addfinalizer(fin)
# 返回前置操作的变量
return test
def test_case(test_addfinalizer):
print("===最新用例===", test_addfinalizer)
运行结果:
yield
与 addfinalizer
用法的区别:
① addfinalizer 可以注册多个终结函数。当注册多个终结函数时,用例的后置操作同时会执行完所有的终结函数。
【注意】终结函数(用例后置操作函数)的执行顺序与其在fixture函数中注册的顺序相反(即先注册的终结函数后执行,后注册的终结函数先执行)
示例:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
@pytest.fixture()
def demo_addfinalizer(request):
print("====setup====")
def fin1():
print("====teardown1====")
def fin2():
print("====teardown2====")
def fin3():
print("====teardown3====")
# 注册fin1、fin2、fin3为终结函数
request.addfinalizer(fin1)
request.addfinalizer(fin2)
request.addfinalizer(fin3)
def test_case1(demo_addfinalizer):
print("====执行用例test_case1====")
def test_case2(demo_addfinalizer):
print("====执行用例test_case2====")
def test_case3(demo_addfinalizer):
print("====执行用例test_case3====")
if __name__ == '__main__':
pytest.main(__file__, '-s')
运行结果: