pytest使用总结及采坑指南

pytest总结

  • pytest一个非常优秀的点就是可以支持扩展很多插件。
  • 安装python工具包时,时长遇到访问连接不到仓库的情况,使用-i命令指定仓库地址,通常我都是选择这个地址:
    https://mirrors.ustc.edu.cn/p...
  • pytest插件如下及功能介绍:
  1. 安装pytest:pip3 install pytest -i https://mirrors.ustc.edu.cn/p...
  2. 由于项目测试中希望重复执行,所以使用pytest-repeat插件
    --count=2, 指定测试的次数,默认是函数级别的测试
    --repeat-scope, 指定重复执行的域.

    • 补充说明:pytest有一个域的概念即scope,分为function、class、module、session
    • 其中function指一个test开头的函数,class指一个Test开头的类,而module指一个test开头的文件,session指这次执行的所有用例。
    • 所以说如果--repeat-scope指定了session则表明是按照session进行重复。
    • 注意:经过测试--xdist命令下不能按照预期的repeat-scope进行执行。
    • 例子:pytest test1.py -s --count=5 --repeat-scope=session
    • 通过在函数上添加@pytest.mark.repeat(count)装饰,指定函数执行次数。
    @pytest.mark.repeat(5)
    def test_02(start, open_baidu):
        print("测试用例test_02")
    
  3. pytest-xdist, 并发执行多个非依赖用例
  • 解释一下,--xdist选项目的是为了节省测试用例的执行时间,使用多核执行测试用例,但是有个前提条件就是这些用例不存在依赖关系,因为依赖关系是不能被保证的,及时有后边提到的ordering、dependancy插件
  • 安装pip3 install pytest-xdist -i https://mirrors.ustc.edu.cn/p...
  • 用法:pytest test.py -n auto指示根据当前cpu信息自动分配合理的核数运行用例,同样可以使用pytest test.py -n 3指定具体的运行核数,并发进程数
  1. pytest相对简单的保证项目用例前后顺序的插件
    pytest-ordering
@pytest.mark.run(order=7)
   def test_delete_port(self, host_ip, module_dict, cfg):
       if "test_create_port" not in module_dict:
           # skip
           pytest.skip("do not have test_create_port result")

       self.delete_port(host_ip, module_dict)

   @pytest.mark.run(order=8)
   def test_delete_subnet(self, host_ip, module_dict, cfg, db_session):
       if "test_create_vpc_subnet" not in module_dict:
           # skip
           pytest.skip("do not have test_create_port result")

       self.delete_subnet(host_ip, module_dict, db_session)

两段代码会先执行7在执行8,如果不指定,则按照名字排序执行。

  1. 自定义参数
  • 有时我们需要根据不同的场景传入一下参数,参考如下代码即可:
# pytest_addoption是pytest已经定义好的fixture(固件)可以直接使用,指定要解析的字段,action表示存储格式  
def pytest_addoption(parser):  
    parser.addoption("--cmdopt", action="store", default="dev.ini", help="my option: type1 or type2")  
    parser.addoption("--concurrency", action="store", default='False', help="my option: concurrency")

# 定义自己的固件,即其他测试用例通过哪个名字获取这个定义的--cmdopt参数
@pytest.fixture(scope="module")
def cmdopt(request):
    return request.config.getoption("--cmdopt")
  1. 生成报告:
  • 使用简单的pytest-html插件
    只需要安装pip3 install pytest-html
    运行命令pytest test.py --html=./report.html,指定输出的文件为report.html报告
  • 使用allure工具,界面好看,功能全,安装复杂

    • 需要安装allure插件及工具
    1. 安装allure brew install allure
    2. 安装插件pip3 install allure-pytest -i https://mirrors.ustc.edu.cn/p...
    3. 执行命令:pytest -v test_vpc_floatingip.py -n auto --count=5 -q --alluredir ./report
    4. allure generate --clean report/ -o allure-results/ #生成html格式文件
    5. allure open ./allure-results/ 打开文件
    6. 备注:allure使用了两种方式来渲染页面,分别是allure open 和 allure serve。前者用于在本地渲染和查看结果,后者用于在本地渲染后对外展示结果,所以要想查看有数据的html内容,需要使用allure open。运行命令 allure open allure-report即可自动打开浏览器(耐心等待一下)展示渲染好的结果,其中allure-report为allure generate生成的结果所在目录。
    7. 有些人会使用pip3 install pytest-allure-adaptor -i https://mirrors.ustc.edu.cn/p... 会报错:
      INTERNALERROR> AttributeError: module 'pytest' has no attribute ‘allure’,卸载安装l allure-pytest,但我这里会报错,所以未使用
    8. 重复执行多次,allure会记录多次的结果,但是总的用例数是不变的,但是某一个用例的重复次数会增加
  1. 重点:我的项目测试用例之间有依赖关系,又不想整合到一起会丢失很多test_case细节,又想要并发将此流程执行多遍,此时简单的使用repeate ordering xdist插件终究不能满足自己的需求,最后只能利用如下方式:
    main函数:
def run(i):
    file_name = '--html=./report/report_{}.html'.format(i[0])
    pytest.main(["-v", "-s", '--log-format="%(asctime)s %(levelname)s %(message)s"',
                 '--log-date-format="%Y-%m-%d %H:%M:%S"', file_name, '', '--alluredir', './report/result', i[1]])
    # pytest.main(['-v', '--alluredir', 'report/result'])


if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        p1 = '--cmdopt={}'.format(sys.argv[1])
        num = int(sys.argv[2])
    else:
        p1 = '--cmdopt=dev.ini'
        num = 1

    import multiprocessing
    pool = multiprocessing.Pool(4)

    _list = [(x, p1) for x in range(num)]
    pool.map(run, _list)
    pool.close()
    pool.join()
  1. 关于日志输出:
    可以通过指定 --log-format="%(asctime)s %(levelname)s %(message)s" 和 --log-date-format="%Y-%m-%d %H:%M:%S"分别指定日志的格式和日志的日期格式
  2. 通过pytest.ini指定pytest运行时参数
    pytest的执行可以分为几种,一种是最常见的pytest test.py形式
    第二种是直接执行pytest,第三种是执行python test.py但此时的test.py内容应该是第7节中的run中的pytest.main的运行形式
    值得注意的是,不管哪种形式pytest都会先找pytest.ini进行加载,如果有覆盖的信息会被覆盖,否则就使用pytest.ini内容

开启日志功能使用log_cli=true

[pytest]
; addopts = -s -v --html=report/report.html --alluredir ./report/result --count=1 -n auto
testpaths = ./
#python_files = test_*.py
#python_classes = Test*
log_cli=true
log_cli_date_format = %Y-%m-%d %H:%M:%S
log_cli_format = %(asctime)s %(levelname)s %(message)s
log_cli_level = INFO
#log_level=NOTSET
log_file = ./logs/pytest-logs.txt
python_functions = test*

参考:
https://www.jianshu.com/p/ddb...
https://www.cnblogs.com/yoyok... 使用skip跳过用例
https://blog.csdn.net/qq_42610167/article/details/101204066?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

你可能感兴趣的:(pytest,python)