pytest中使用conftest做测试前置和参数化

pytest中比较高阶的应用是,使用conftest去做测试前置工作、测试收尾工作和参数化。conftest是pytest的一个组件,用于配置测试环境和参数。通过conftest, 可以创建一个可复用的测试配置文件,以便在多个测试模块之间共享配置信息。即,conftest主要用来存放fixture,管理一些全局的fixture. 

适用场景

  •   多个测试用例文件(test_*.py)的所有用例都需要用登录功能作为前置操作,那就不能把登录功能写到某个用例文件中去了,这个时候就可以把登录功能写成一个fixture,放到conftest.py里
  • 多个case共享一套测试数据
  • 多个case共享配置信息

conftest.py配置fixture注意事项

  • pytest会默认读取conftest.py里面所有的fixture
  • conftest.py文件名称是固定的,不能改动
  • conftest.py只对同一个package下的所有测试用例生效
  • 不同目录可以有自己的conftest.py, 一个项目可以有多个conftest.py
  • 测试用例文件中不需要手动import conftest.py, pytest会自动查找
  • 在conftest.py文件中,可以定义函数、类和变量,以供测试用例中使用。这些配置可以通过参数传递给测试用例。配合测试用例中的pytest.mark.parametrize装饰器来传递参数。
  • conftest.py如果在项目根目录下,那就是对整个项目下的测试用例生效

conftest结合fixture使用

  • scope参数为session: 所有测试.py文件执行前执行一次
  • scope参数为module: 每一个测试.py文件执行前都会执行一次conftest文件中的fixture
  • scope参数为class: 每一个测试文件中的测试类执行前都会执行一次conftest文件中的fixture
  • scope参数为function:所有文件的测试用例执行前都会执行一次conftest文件中的fixture,默认scope为function.

例子:

conftest.py

data = excel_util.get_cell_range_data(CASE_BASE_PATH, CASE_INFO_SHEET, 2, 2, 1, 10)


@pytest.fixture(params=data)  # 这里使用了参数化
def login(request):   # 登录功能,返回uuid, token
    param = request.param
    url = param['url']
    api = param['api']
    params = param['parameter']
    params = substitution_tool.var_substitute(params, '登录')
    globalVar = param['globalVar']  
    url += api + '&' + params
    res = request_util.send_httprequest('post', url).json()  
    print("res=", res)
    
    gv = globalVar_util.saveGlobals(res, globalVar)  #这里把uuid,token保存到全局变量中
    yield gv # 返回包含有uuid,token的字典gv

这是一个封装登录功能的fixture, 通过params=data先传入登录需要的用户名和密码数据,然后经过fixture实现返回uuid,token的功能。

conftest.py

@pytest.fixture()
def case_info(request):   # 获取测试用例的数据
    param = request.param
    return param

这是一个结合pytest.mark.parametrize装饰器实现参数传递的fixture, 可以读取excel表格中的测试用例信息。

看测试文件中的测试方法:

data_login_state = excel_util.get_cell_range_data(CASE_BASE_PATH, CASE_INFO_SHEET, 3, 6, 1, 9)


@allure.severity("normal")
@pytest.mark.parametrize("case_info", data_login_state, indirect=True)
def test_login_tai(case_info, login):
    caseId = case_info['caseId']
    apiName = case_info['apiName']
    caseTitle = case_info['caseTitle']
    params = case_info['parameter']
    '''
    for key in login.keys():
        value = login.get(key)
        if key in params:
            params = params.replace('${'+key+'}', str(value))
    '''
    params = substitution_tool.gv_substitute(params)
    url = case_info['url']
    api = case_info['api']
    url += api + '&' + params
    print("url=", url)
    print(f"caseId: {caseId}, apiName:{apiName}, caseTitle:{caseTitle} begins to test!")
    logger.info(f"caseId: {caseId}, apiName:{apiName}, caseTitle:{caseTitle} starts to test!")
    assertFields = case_info['assertFields']
    res = request_util.send_httprequest('post', url).json()
    assert_util.assert_result(res, assertFields)

这里就结合pytest.mark.parametrize装饰器实现参数的传递,这里方法test_login_tai使用了两个fixture,一个是login, 一个是case_info, 两个fixture一块使用,既接收到了login返回的uuid,token, 又实现了测试用例的参数化。其中,indirect=True代表case_info是作为函数传递给test_login_tai方法的,不是作为变量。

最后使用pytest命令去执行pytest --html=./testreport.html

测试执行情况如上,日志信息有caseId, apiName, caseTitle.

生成的testreport.html测试报告:

上一篇:CSS核心(上)


下一篇:LNMP和Discuz论坛