示例场景
假设我们有一个提交数据的操作,希望在测试用例中管理提交的数据状态,并确保在整个测试过程中能正确访问这些数据。
1.使用全局变量 global
@pytest.fixture(scope='function')
def crud(self, init_admin, request):
crud = Crud(init_admin)
yield crud
if recordid:
crud.delete(recordIds=[recordid])
@pytest.mark.parametrize('fieldData,fieldName,expected', read_crud())
def test_submit(self, crud, fieldData, fieldName, expected, request):
result = crud.submit(fieldData=fieldData)
global recordid # recordid设置为全局变量
recordid = result['data']
query_reponse = crud.detail(recordId=recordid)
2.使用 request.session
import pytest
import json
from lib.util.read_data import read_crud
from lib.webapi.crud import Crud
@pytest.fixture(scope='function')
def crud(init_admin, request):
# 初始化 Crud 对象
crud = Crud(init_admin)
yield crud # 返回给测试用例使用
# 通过 request 对象获取 recordid
recordid = getattr(request.session, 'recordid', None)
if recordid:
# 清理操作,删除对应的记录
crud.delete(recordIds=[recordid])
print(f"清理记录 ID: {recordid}")
@pytest.mark.parametrize('fieldData,fieldName,expected', read_crud())
def test_submit(crud, fieldData, fieldName, expected, request):
# 提交数据
result = crud.submit(fieldData=fieldData)
# 获取返回的 recordid 并存储到 request.session
recordid = result['data']
request.session.recordid = recordid # 设置 session 级的 recordid
# 查询记录详情
query_response = crud.detail(recordId=recordid)['data']['record']['rowData'][fieldName]
# 验证查询结果是否与预期一致
assert query_response == expected, f"预期值:{expected},实际值:{query_response}"
解释
global 关键字:
1)global 关键字用于在函数内部声明某个变量是全局变量,从而可以在函数中修改其值。这是因为在 Python 中,函数内部默认会创建局部变量,而使用 global 可以让函数内部的变量引用全局变量。
全局变量 recordid:
2)recordid 是一个在模块级别定义的全局变量,用于存储从 crud.submit() 函数中获取的记录 ID。
在 test_submit 函数中,使用 global 关键字声明 recordid 为全局变量,允许函数内部修改它的值。
全局变量的使用:
3)在测试用例中,recordid 被设置为 crud.submit() 返回结果中的记录 ID。
由于 recordid 是全局变量,在测试用例的 yield 后,这个值可以被 fixture 的清理代码使用。
问题及建议:
4)全局变量的潜在问题:使用全局变量可能导致状态污染或在多线程环境中出现意外结果,尤其是在并发测试或多个测试用例同时运行时。全局变量在测试执行期间会被共享,因此可能会影响测试的独立性和结果的可预测性。
改进建议:建议使用 request.session 或 fixture 的返回值来替代全局变量,以保持测试用例的隔离性和可靠性。例如,可以在 fixture 中使用 request 对象存储 recordid,并在清理阶段使用它。
request.session 示例:
1)定义与初始化:
request.session 需要在 fixture 中显式定义和初始化,通常是一个字典或自定义对象。
在你的示例代码中,request.session 是用来存储 recordid 的,以便在测试用例和 fixture 之间共享数据。
2)作用:
request.session 用于在同一个测试会话中的不同测试用例之间共享数据。在测试用例执行期间,数据存储在 request.session 中,可以在测试结束后用于清理操作。
通过 request.session,你可以在 fixture 和测试用例之间传递信息,如 recordid,确保测试数据的管理和清理能够协调一致。
3)使用方式:
在 fixture 中,你可以创建和初始化 request.session,例如:request.session = {}。
在测试用例中,你可以通过 request.session 访问和修改数据。例如:request.session[‘recordid’] = recordid。
在测试结束时,fixture 可以读取 request.session 中的数据并进行清理操作,例如:删除记录。
4)优点:
数据隔离:request.session 确保数据在测试用例和 fixture 之间共享,而不会影响其他测试用例或测试会话。
灵活性:可以在 fixture 中创建自定义的 session 结构,以适应复杂的测试需求。