目录
1、conftest.py作用范围
conftest.py 文件名称是固定的,pytest 会自动识别该文件,可以理解成一个专门存放 fixture 的配置文件。
一个工程下可以建多个 conftest.py 的文件,一般在工程根目录下设置的 conftest 文件起到全局作用。在不同子目录下也可以放 conftest.py 的文件,作用范围只能在该层级以及以下目录生效。
conftest.py 配置 fixture 注意事项:
-
pytest 会默认读取 conftest.py 里面的所有 fixture。
-
conftest.py 文件名称是固定的,不能改动。
-
conftest.py 只对同一个 package 下的所有测试用例生效。
-
不同目录可以有自己的 conftest.py,一个项目中可以有多个 conftest.py。
-
测试用例文件中不需要手动 import conftest.py,pytest 会自动查找。
示例:
目录结构:
1、My_pytest_Demo/conftest.py
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
@pytest.fixture(scope='session', autouse=True)
def login():
print("====准备登录====")
2、My_pytest_Demo/fixture_chapter/conftest.py
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
@pytest.fixture(scope='session', autouse=True)
def bai_du():
print("====登录成功====")
3、My_pytest_Demo/fixture_chapter/login_demo.py
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
class TestCase:
def test_case(self):
print("====执行用例====")
if __name__ == '__main__':
pytest.main(['-s', 'login_demo.py'])
4、运行结果:
执行login_demo.py文件,根目录下的conftest.py先执行,之后执行fixture_chapter目录下的conftest.py,最后才执行login_demo.py
2、yield实现teardown
前面章节讲的其实都是 setup 的操作,接下来讲解怎样来实现 teardown 的操作。
用 fixture 实现 teardown 并不是一个独立的函数,而是用 yield 关键字来开启 teardown 操作。
-
当 pytest.fixture(scope="session") 时,作用域是整个测试会话,即开始执行 pytest 到结束测试只会执行一次。
-
当 pytest.fixture(scope="function") 时,pytest 的 yield 类似 unittest 的 teardown。每个方法(函数)都会执行一次。
-
当 pytest.fixture(scope="module") 时,module 作用是整个 .py 文件都会生效(整个文件只会执行一次),用例调用时,参数写上函数名称就可以。
1、创建test_fixture4.py文件
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
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)
2、运行结果:
注意要点:
-
如果 yield 前面的代码,即 setup 部分已经抛出异常,则不会执行 yield 后面的 teardown 内容。
-
如果测试用例抛出异常,yield 后面的 teardown 内容还是会正常执行。
3、yield+with的结合
yield 也可以配合 with 语句使用。
创建test_fixture5.py文件
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
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
4、addfinalizer终结函数
除了 yield 可以实现 teardown,在 request-context 对象中注册 addfinalizer 方法也可以实现终结函数。
1、创建test_fixture6.py文件
在用法上,addfinalizer 跟 yield 是不同的,需要你去注册作为终结器使用的函数。例如:增加一个函数 fin,并且注册成终结函数。
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
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)
2、运行结果:
yield 与 addfinalizer 的区别:
1、addfinalizer 可以注册多个终结函数。
创建test_fixture_7.py文件
脚本代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
微信公众号:AllTests软件测试
"""
import pytest
@pytest.fixture()
def demo_addfinalizer(request):
print("====setup====")
def fin1():
print("====teardown1====")
def fin2():
print("====teardown2====")
def fin3():
print("====teardown3====")
# 注册demo_addfinalizer为终结函数
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====")
运行结果:
注册的3个函数都被执行了,但是要注意的是执行顺序,与注册的顺序相反。
2、当setup的代码执行错误,addfinalizer依旧会执行。