当前位置:   article > 正文

tep支持pytest-xdist分布式执行用例及合并Allure报告

allure多次报告合并

tep近期更新频率较快,一方面是作者在积极投入到tep工具开发中;另一方面是我们聚集了20位小伙伴,一起合力打造EasyPytest测试平台,teprunner的FastAPI升级版本,依托于tep,帮你高效管理pytest测试用例。陆续也会有平台开发日志发布,欢迎持续关注。

预览内容:

1、pytest-xdist分布式执行用例,合并Allure报告;

2、global_vars全局变量配置;

预览项目:https://github.com/dongfanger/tep-template.git

分布式执行用例

借助于pytest-xdist,在命令行执行时添加参数-n auto

pytest -n auto

pytest-xdist会自动根据本地机器硬件配置,设置最优并发,并分发用例,分布式执行。

测试时先运行main.py,然后在case100目录下执行pytest -n auto --tep-reports

第一次串行,第二次xdist并行:

执行时间从50s一下降到5s,性能提升还是非常的明显。

合并Allure报告

pytest-xdist分布式执行,只要把allure源文件,也就是那一堆json文件,存到同一个目录下,报告的数据就是一体的,不需要单独合并。但是有个问题,tep封装了--tep-reports 命令行参数一键生成Allure报告,背后的逻辑是在pytest_sessionfinish hook函数里面实现的,分布式执行时,每个xdist的node都是一个单独的session,多个node就会生成多份报告:

c

10个node生成了11份报告,其中1份master节点生成的。pytest-xdist的原理如图所示:

master节点不运行任何测试,只是通过一小部分消息与节点通信。子节点执行后会通过workeroutput把数据回传给master节点。所以只需要通过是否有workeroutput属性来判断master节点:

  1. def _is_master(config):
  2. """
  3. pytest-xdist分布式执行时,判断是主节点master还是子节点
  4. 主节点没有workerinput属性
  5. """
  6. return not hasattr(config, 'workerinput')

然后只在主节点的pytest_sessionfinish,生成1次报告,就能避免生成多份报告。这样在xdist分布式执行模式下,--tep-reports也只会生成1份合并后的包含所有测试用例的Allure HTML报告。

完整实现代码:

  1. import time
  2. import shutil
  3. import allure_commons
  4. from allure_commons.logger import AllureFileLogger
  5. from allure_pytest.listener import AllureListener
  6. from allure_pytest.plugin import cleanup_factory
  7. reports_path = os.path.join(Project.root_dir, "reports")
  8. allure_source_dir_name = ".allure.source.temp"
  9. allure_source_path = os.path.join(reports_path, allure_source_dir_name)
  10. def _tep_reports(config):
  11. """
  12. --tep-reports命令行参数不能和allure命令行参数同时使用,否则可能出错
  13. """
  14. if config.getoption("--tep-reports") and not config.getoption("allure_report_dir"):
  15. return True
  16. return False
  17. def _is_master(config):
  18. """
  19. pytest-xdist分布式执行时,判断是主节点master还是子节点
  20. 主节点没有workerinput属性
  21. """
  22. return not hasattr(config, 'workerinput')
  23. def pytest_addoption(parser):
  24. """
  25. allure测试报告 命令行参数
  26. """
  27. parser.addoption(
  28. "--tep-reports",
  29. action="store_const",
  30. const=True,
  31. help="Create tep allure HTML reports."
  32. )
  33. def pytest_configure(config):
  34. """
  35. 这段代码源自:https://github.com/allure-framework/allure-python/blob/master/allure-pytest/src/plugin.py
  36. 目的是生成allure源文件,用于生成HTML报告
  37. """
  38. if _tep_reports(config):
  39. if os.path.exists(allure_source_path):
  40. shutil.rmtree(allure_source_path)
  41. test_listener = AllureListener(config)
  42. config.pluginmanager.register(test_listener)
  43. allure_commons.plugin_manager.register(test_listener)
  44. config.add_cleanup(cleanup_factory(test_listener))
  45. clean = config.option.clean_alluredir
  46. file_logger = AllureFileLogger(allure_source_path, clean) # allure_source
  47. allure_commons.plugin_manager.register(file_logger)
  48. config.add_cleanup(cleanup_factory(file_logger))
  49. def pytest_sessionfinish(session):
  50. """
  51. 测试运行结束后生成allure报告
  52. """
  53. if _tep_reports(session.config):
  54. if _is_master(session.config): # 只在master节点才生成报告
  55. # 最近一份报告的历史数据,填充allure趋势图
  56. if os.path.exists(reports_path):
  57. his_reports = os.listdir(reports_path)
  58. if allure_source_dir_name in his_reports:
  59. his_reports.remove(allure_source_dir_name)
  60. if his_reports:
  61. latest_report_history = os.path.join(reports_path, his_reports[-1], "history")
  62. shutil.copytree(latest_report_history, os.path.join(allure_source_path, "history"))
  63. current_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
  64. html_report_name = os.path.join(reports_path, "report-" + current_time)
  65. os.system(f"allure generate {allure_source_path} -o {html_report_name} --clean")
  66. shutil.rmtree(allure_source_path)

global_vars全局变量

在使用环境变量模版时,有些变量需要在多个模版重复设置,tep新增了global_vars全局变量fixture,可以将重复设置的变量,定义在resources/global_vars.yaml

然后引用global_vars fixture取值即可:

  1. def test(global_vars):
  2. print(global_vars["desc"])

实现代码:

  1. @pytest.fixture(scope="session")
  2. def global_vars():
  3. """全局变量,读取resources/global_vars.yaml,返回字典"""
  4. class Clazz(TepVars):
  5. def dict_(self):
  6. with open(os.path.join(Config.project_root_dir, "resources", "global_vars.yaml")) as f:
  7. return yaml.load(f.read(), Loader=yaml.FullLoader)
  8. return Clazz().dict_()

参考资料:

https://github.com/pytest-dev/pytest-xdist

如何从pytest-xdist节点获取数据 https://www.cnblogs.com/se7enjean/p/15924317.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/638997
推荐阅读
相关标签
  

闽ICP备14008679号