Pytest

  1. # 安装pytest:
    pip install pytest
    # 升级pytest 
    pip install -U pytest 
    # 查看pytest版本
    pytest --version
    # 查看已安装包列表
    pip list
    # 查看pytest帮助文档
    pytest -h
    # 安装第三方插件 
    pip install pytest-sugar 
    pip install pytest-rerunfailures 
    pip install pytest-xdist 
    pip install pytest-assume 
    pip install pytest-html
    
  2. @pytest.mark.skipif

    “@pytest.mark.skipif” 通常是在 Python 的 pytest 测试框架中使用的一个装饰器。 “skipif” 表示根据指定的条件来决定是否跳过(不执行)被装饰的测试函数。

  3. pytest.raise

    pytest中,pytest.raises()是一个用于测试代码是否引发特定异常的上下文管理器。

    import pytest
    
    def test_function_that_raises_exception():
        with pytest.raises(TypeError):
            # 这里的代码预期会引发 TypeError 异常
            some_function_that_should_raise_type_error()
    

    在上述代码中,当执行some_function_that_should_raise_type_error()时,如果它引发了TypeError异常,那么这个测试用例将通过;如果没有引发这个异常或者引发了其他异常,测试用例将失败。

  4. pytest测试用例的识别与运行

    • 发现用例的规则

      a) 文件test_.py开头和_test.py结尾

      b) Test开头的类中test开头的方法(测试类不能带有__init__方法)

      c) 模块中test开头的函数(可以不在class中)

      d)包中存在init方法

    • 注意点:

      pytest是以方法为单位发现用例的,写不写测试类根本不重要
      在哪个目录下执行pytest就在哪个目录下按照上述规则去查找

    • 自定义查找规则:pytest.ini

      在pytest.ini中写入addopts = -p no:warnings

      忽视所有的警告

  5. 参数:

    • pytest / py.test
    • 打印详细运行日志信息:pytest -v (最高级别信息-verbose)
    • s是带控制台输出结果,也是输出详细,可以打印测试用例中print的输出:pytest -v -s 文件名
    • 执行单独一个pytest模块:pytest 文件名.py
    • 运行某个模块里面某个类:pytest 文件名.py::类名
    • 运行某个模块里面某个类里面的方法:pytest 文件名.py::类名::方法名
    • 跳过某个用例:pytest -k "类名 and not 方法名",如pytest -k "TestDemo and not test_one"
    • 运行带有某标记的测试用例(pytest.mark.标记名):pytest -m 标记名
    • 一旦运行到报错就停止运行:pytest -x 文件名
    • 当错误达到num的时候就停止运行:pytest --maxfail=[num]
  6. 失败重新运行
    场景:测试失败后要重新运行n次,要在重新运行之间添加延迟时间,间隔n秒再运行。

    安装:pip install pytest-rerunfailures

    执行:

    • 测试失败后重新运行3次:pytest --reruns 3 -v -s test_class.py
    • 测试失败后重新运行5次且每次重新运行间隔1秒:pytest -v --reruns 5 --reruns-delay 1
    • 或加入装饰器@pytest.mark.flaky(reruns = 1)
    • 或可以加入pytest.ini中(addopts = -p no:warnings -s -v --reruns 2 --reruns-delay 2)
    • 尝试加入main中不好用
  7. 多次断言,不中断

    一个方法中写多条断言,通常第一条断言失败,下面的断言也不执行了。但是我们希望即使第一条断言失败,后续断言还是继续执行。

    pip install pytest-assume
    
        def test_assume(self):
            pytest.assume(1==2)
            pytest.assume(1<3)
            pytest.assume(1==1)
    
  8. pytest.ini

    是 pytest 测试框架的配置文件,用于定义 pytest 的运行配置。

    它通常位于项目的根目录或指定的测试目录中,并且可以包含各种配置选项,以适应不同项目和测试环境的需求。

    以下是一些常见的配置选项:

    • addopts:添加额外的命令行选项。多条命令空格分割
    • testpaths:指定测试用例的文件或目录路径。
    • python_files:指定包含 Python 测试模块的文件名匹配模式。
    • plugins:启用或禁用 pytest 插件
    • markers:定义标记,用于标记测试用例。
    • fixture:配置测试用例的fixture。
    • cache:配置缓存,用于加速测试执行。
    • env:设置环境变量。
    • setup.cfg:指定要使用的 setup.py 脚本
  9. conftest

    conftest.py 是 pytest 特有的测试配置文件,可以理解成一个专门放 fixture(设备、工具)的地方。一个工程下可以建多个 conftest.py 文件,通常在工程根目录下设置一个 conftest 文件,这样会起到一个全局的作用;也可以在不同的子目录下放 conftest.py ,这样作用范围只能在该层级的子目录下生效。

    fixture 是在测试函数运行前后,由 pytest 执行的外壳函数,类似 unittest 中的 setup/teardown

    conftest.py配置fixture注意事项

    • pytest会默认读取conftest.py里面的所有fixture
    • conftest.py 文件名称是固定的,不能改动
    • conftest.py只对同一个package下的所有测试用例生效
    • 不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py
    • 测试用例文件中不需要手动import conftest.py,pytest会自动查找
    • 所有同目录测试文件运行前都会执行conftest.py文件;
  10. pytest.mark.parametrize

    pytest.mark.parametrize 是 pytest 框架中的一个装饰器,用于在测试用例中参数化。它允许你为一个测试函数提供多个不同的参数组合,并在执行测试时自动遍历这些组合。

    我们可以通过ids对参数用例进行描述,如果不设置ids,就默认参数值表示.

       @pytest.mark.parametrize('in_data', eval(re_data), ids=[i['detail'] for i in TestData])
        def test_login(self, in_data, case_skip):
            """
            :param :
            :return:
            """
            res = RequestControl(in_data).http_request()
            TearDownHandler(res).teardown_handle()
    
  11. pytest中的fixture

    1. fixture可以通过函数实现,并使用装饰器@pytest.fixture进行装饰。fixture的作用范围可以是测试函数、测试类、测试模块或整个测试会话。在fixture函数中,可以编写前置准备工作代码和后置清理工作代码,并使用yeild关键字来区分前后置代码。

      可以将配置提取到conftest配置类中

      后置处理器用yield作为分割。

      @pytest.fixture()
      def login():
          print("登录。。。。。。。。")
      
          yield#yield作为分界线,下面是后置处理器
          print("退出登录")
      # 将方法名带入到需要前置的方法的参数里。
      def test_01(login):
          str = "huahua"
          assert "u" in str
      def test_02():
          str = "yy"
          assert "y" in str
      def test_03(login):
          str = "yy0"
          assert "y" in str
      if __name__ == '__main__':
          pytest.main(['-vs'])
      
    2. 在conftest使用autouse参数所有的test_*自动执行fixture,无需将fixture写入到方法参数中

      @pytest.fixture(scope="session", autouse=True)
      def work_login_init():
          """
          获取登录的cookie
          :return:
          """
      
          url = "https://www.wanandroid.com/user/login"
          data = {
              "username": 18800000001,
              "password": 123456
          }
          headers = {'Content-Type': 'application/x-www-form-urlencoded'}
          # 请求登录接口
      
          res = requests.post(url=url, data=data, verify=True, headers=headers)
          response_cookie = res.cookies
      
          cookies = ''
          for k, v in response_cookie.items():
              _cookie = k + "=" + v + ";"
              # 拿到登录的cookie内容,cookie拿到的是字典类型,转换成对应的格式
              cookies += _cookie
              # 将登录接口中的cookie写入缓存中,其中login_cookie是缓存名称
          CacheHandler.update_cache(cache_name='login_cookie', value=cookies)
      
    3. 四种作用域
      • function:每一个函数或方法都会调用
      • class:每一个类调用一次,一个类中可以有多个方法
      • module:每一个.py文件调用一次,该文件内又有多个function和class
      • session:多个文件调用一次,可以跨.py文件调用(通常这个级别会结合conftest.py文件使用)
  12. pytest的执行流程

    pytest启动后,会先加载.ini文件读取ini文件中设置的对应参数,并给框架内部的变量赋值

    加载完.ini文件,会去加载内部的conftest.py文件

    最后执行测试用例

  13. 如何做冒烟测试?

    在pytest.ini中定义好markers的类别

    markers =
        smoke: 冒烟测试
        regression: 回归测试
    

    使用装饰器@pytest.mark.smoke定义该测试用例类别

    在pytest.ini中执行 -m smoke

    addopts = -p no:warnings -m smoke
    
  14. 如何统计测试结果

    统计测试结果的目的是存放在内存中,随时使用,可以进行发送邮件等操作

    pytest_terminal_summary是一个Pytest钩子函数,它在测试执行完成后被调用

    只需在conftest.py中写个 pytest_terminal_summary 函数收集测试结果

    钩子函数是一种在程序执行过程中的特定点被调用的函数。它们允许开发者在程序的特定阶段插入自己的代码,以执行自定义的操作或修改程序的行为。

    钩子函数的实现通常由框架或系统提供,开发者只需注册或实现相应的钩子函数,系统在特定的时间点或事件发生时会自动调用这些函数

    def pytest_terminal_summary(terminalreporter, exitstatus, config):
        '''收集测试结果'''
        print(terminalreporter.stats)
        print("total:", terminalreporter._numcollected)
        print('passed:', len(terminalreporter.stats.get('passed', [])))
        print('failed:', len(terminalreporter.stats.get('failed', [])))
        print('error:', len(terminalreporter.stats.get('error', [])))
        print('skipped:', len(terminalreporter.stats.get('skipped', [])))
        # terminalreporter._sessionstarttime 会话开始时间
        duration = time.time() - terminalreporter._sessionstarttime
        print('total times:', duration, 'seconds')
    
posted @ 2024-05-31 09:21  疯啦吧你  阅读(18)  评论(0编辑  收藏  举报