Python_pytest详解

1.Pytest安装和介绍

1.1 Pytest介绍

pytest是python的一种单元测试框架,同自带的Unittest测试框架类似,相比于Unittest框架使用起来更简洁,效率更高。

Pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library. `

1.2 Pytes安装

1.安装包安装

1.进入下载包路径
2.python setup install
3.安装出现权限问题:
3.1.mac/linux 添加sudo,运行:sudo python setup install
3.2.windows 管理员方式运行cmd窗口,运行:python setup install

2.命令行安装

1.mac/linux:sudo pip3 install -U pytest # -U:可以理解为--upgrade,表示已安装就升级为最新版本
2.管理员方式运行cmd:pip3 install -U pytest

2.安装成功校验:

1.进入命令行
2.运行:pytest --version # 会展示当前已安装版本

1.3 Pytest文档

存在手机里,没事就拿出来读一读,看一看.说实话,我的英文能力很渣,学这个东西感觉很难,不过一切慢慢来吧.为了一份好的工作,为了技术的提升,我给自己的目标是:一周写出一小篇文章.必须有深度,让别人能看懂,转行真的不容易.记住:有时间多看看文档,毕竟了解一些先进的技术是必须看英文文档的.

链接在这里: https://docs.pytest.org/en/latest/contents.html

1.4 Pytest运行方式

 # file_name: test_abc.py
 import pytest # 引入pytest包
 def test_a(): # test开头的测试函数
     print("------->test_a")
     assert 1 # 断言成功
 def test_b():
     print("------->test_b")
     assert 0 # 断言失败
 if __name__ == '__main__':
        pytest.main("-s  test_abc.py") # 调用pytest的main函数执行测试

1.测试类主函数模式

  pytest.main("-s  test_abc.py")

2.命令行模式

  pytest 文件路径/测试文件名
  例如:pytest ./test_abc.py
在pytest框架中,有如下约束:

所有的单测文件名都需要满足test_.py格式或test.py格式。
在单测文件中,可以包含test
开头的函数,也可以包含Test开头的类。
在单测类中,可以包含一个或多个test_开头的函数。
此时,在执行pytest命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行。

2.Pytest的setup和teardown函数

1.setup和teardown主要分为:模块级,类级,功能级,函数级。
2.存在于测试类内部
代码示例:

  • 函数级别setup()/teardown()

运行于测试方法的始末,即:运行一次测试函数会运行一次setup和teardown

import pytest
class Test_ABC:
  # 函数级开始
  def setup(self):
      print("------->setup_method")
  # 函数级结束
  def teardown(self):
      print("------->teardown_method")
  def test_a(self):
      print("------->test_a")
      assert 1
  def test_b(self):
      print("------->test_b")
if __name__ == '__main__':
              pytest.main("-s  test_abc.py")
执行结果:
  test_abc.py 
  ------->setup_method # 第一次 setup()
  ------->test_a
  .
  ------->teardown_method # 第一次 teardown()
  ------->setup_method # 第二次 setup()
  ------->test_b
  .
          ------->teardown_method # 第二次 teardown()
  • 2.2.类级别

运行于测试类的始末,即:在一个测试内只运行一次setup_class和teardown_class,不关心测试类内有多少个测试函数。
代码示例:

import pytest
class Test_ABC:
   # 测试类级开始
   def setup_class(self):
       print("------->setup_class")
   # 测试类级结束
   def teardown_class(self):
       print("------->teardown_class")
   def test_a(self):
       print("------->test_a")
       assert 1
   def test_b(self):
       print("------->test_b")
          if __name__ == '__main__':
              pytest.main("-s  test_abc.py")
执行结果:
  test_abc.py 
  ------->setup_class # 第一次 setup_class()
  ------->test_a
  .
  ------->test_b
  F 
          ------->teardown_class # 第一次 teardown_class()

3.Pytest配置文件

pytest的配置文件通常放在测试目录下,名称为pytest.ini,命令行运行时会使用该配置文件中的配置.

#配置pytest命令行运行参数
   [pytest]
    addopts = -s ... # 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数配置测试搜索的路径
    testpaths = ./scripts  # 当前目录下的scripts文件夹 -可自定义
#配置测试搜索的文件名称
    python_files = test*.py 
#当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件 -可自定义
配置测试搜索的测试类名
    python_classes = Test_*  

   #当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类 -可自定义
配置测试搜索的测试函数名
  
    python_functions = test_*

#当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类内,以test_开头的方法 -可自定义

4 Pytest常用插件

插件列表网址:https://plugincompat.herokuapp.com
包含很多插件包,大家可依据工作的需求选择使用。

4.1 前置条件:

1.文件路径:

- Test_App
- - test_abc.py
- - pytest.ini

2.pyetst.ini配置文件内容:

  [pytest]
# 命令行参数
 addopts = -s
# 搜索文件名
 python_files = test_*.py
 # 搜索的类名
 python_classes = Test_*
 #搜索的函数名
    python_functions = test_*

4.2 Pytest测试报告

通过命令行方式,生成xml/html格式的测试报告,存储于用户指定路径。插件名称:pytest-html

使用方法: 命令行格式:pytest --html=用户路径/report.html

示例:
import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
        print("------->teardown_class")
    def test_a(self):
        print("------->test_a")
        assert 1
    def test_b(self):
            print("------->test_b")
            assert 0 # 断言失败```
运行方式:
1.修改Test_App/pytest.ini文件,添加报告参数,即:addopts = -s --html=./report.html 
    # -s:输出程序运行信息
    # --html=./report.html 在当前目录下生成report.html文件
    ️ 若要生成xml文件,可将--html=./report.html 改成 --html=./report.xml
2.命令行进入Test_App目录
3.执行命令: pytest
执行结果:
    1.在当前目录会生成assets文件夹和report.html文件

5.pytest的高阶用法(一)

前置条件:

1.文件路径:

Test_App
    - - test_abc.py
    - - pytest.ini

2.pyetst.ini配置文件内容:


[pytest]
  命令行参数
 addopts = -s
 搜索文件名
 python_files = test*.py
  搜索的类名
 python_classes = Test*
搜索的函数名
 python_functions = test_*

5.1pytest之fixture

fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。

方法:fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用参数:

 scope:被标记方法的作用域
 function" (default):作用于每个测试方法,每个test都运行一次
"class":作用于整个类,每个class的所有test只运行一次
 "module":作用于整个模块,每个module的所有test只运行一次
 "session:作用于整个session(慎用),每个session只运行一次
 params:(list类型)提供参数数据,供调用标记方法的函数使用
 autouse:是否自动运行,默认为False不运行,设置为True自动运行

5.2fixture第一个例子(通过参数引用)

示例:

class Test_ABC:
    @pytest.fixture()
    def before(self):
        print("------->before")
    def test_a(self,before): # ️ test_a方法传入了被fixture标识的函数,已变量的形式
        print("------->test_a")
        assert 1
if __name__ == '__main__':
    pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py 
        ------->before # 发现before会优先于测试函数运行
        ------->test_a
         .

5.3.fixture第二个例子(通过函数引用)

示例:
import pytest
@pytest.fixture() # fixture标记的函数可以应用于测试类外部
def before():
    print("------->before")
@pytest.mark.usefixtures("before")
class Test_ABC:
    def setup(self):
        print("------->setup")
    def test_a(self):
        print("------->test_a")
        assert 1
if __name__ == '__main__':
          pytest.main("-s  test_abc.py")
  执行结果:
      test_abc.py 
      ------->before # 发现before会优先于测试类运行
      ------->setup
      ------->test_a
      .

5.4.fixture第三个例子(默认设置为运行)

示例:

 import pytest
 @pytest.fixture(autouse=True) # 设置为默认运行
 def before():
     print("------->before")
 class Test_ABC:
     def setup(self):
         print("------->setup")
     def test_a(self):
         print("------->test_a")
         assert 1
 if __name__ == '__main__':
     pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py 
    ------->before # 发现before自动优先于测试类运行
    ------->setup
    ------->test_a
        .

5.5.fixture第四个例子(设置作用域为function)

示例:

    import pytest
    @pytest.fixture(scope='function',autouse=True) # 作用域设置为function,自动运行
    def before():
        print("------->before")
    class Test_ABC:
        def setup(self):
            print("------->setup")
        def test_a(self):
            print("------->test_a")
            assert 1
        def test_b(self):
            print("------->test_b")
            assert 1
    if __name__ == '__main__':
        pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py
        ------->before # 运行第一次
        ------->setup
        ------->test_a
        .------->before # 运行第二次
        ------->setup
        ------->test_b
        .

5.6.fixture第五个例子(设置作用域为class)

示例:

    import pytest
    @pytest.fixture(scope='class',autouse=True) # 作用域设置为class,自动运行
    def before():
        print("------->before")
    class Test_ABC:
        def setup(self):
            print("------->setup")
        def test_a(self):
            print("------->test_a")
            assert 1
        def test_b(self):
            print("------->test_b")
            assert 1
    if __name__ == '__main__':
        pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py
    ------->before # 发现只运行一次
    ------->setup
        ------->test_a
        .
        ------->setup
        ------->test_b
        .

5.7.fixture第六个例子(返回值)

示例一:


    import pytest
    @pytest.fixture()
    def need_data():
        return 2 # 返回数字2

    class Test_ABC:

        def test_a(self,need_data):
            print("------->test_a")
            assert need_data != 3 # 拿到返回值做一次断言

    if __name__ == '__main__':
        pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py 
    ------->test_a
    .
``

示例二:

import pytest
@pytest.fixture(params=[1, 2, 3])
def need_data(request): # 传入参数request 系统封装参数
    return request.param # 取列表中单个值,默认的取值方式
class Test_ABC:

    def test_a(self,need_data):
        print("------->test_a")
        assert need_data != 3 # 断言need_data不等于3

if __name__ == '__main__':
    pytest.main("-s  test_abc.py")

 执行结果:
      # 可以发现结果运行了三次
      test_abc.py 
      1
      ------->test_a
      .
      2
      ------->test_a
      .
      3
      ------->test_a
      F

6.Pytest高阶用法(二)

前置条件:

1.文件路径:

- Test_App
- - test_abc.py
- - pytest.ini

2.pyetst.ini配置文件内容:

[pytest]
命令行参数
addopts = -s
搜索文件名
python_files = test_*.py
 搜索的类名
python_classes = Test_*
 搜索的函数名
python_functions = test_*

6.1.跳过测试函数

根据特定的条件,不执行标识的测试函数.
 方法:
     skipif(condition, reason=None)
 参数:
     condition:跳过的条件,必传参数
     reason:标注原因,必传参数
 使用方法:
     @pytest.mark.skipif(condition, reason="xxx") 

示例:

import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
        print("------->teardown_class")
    def test_a(self):
        print("------->test_a")
        assert 1
    @pytest.mark.skipif(condition=2>1,reason = "跳过该函数") # 跳过测试函数test_b
    def test_b(self):
        print("------->test_b")
            assert 0
执行结果:
   test_abc.py 
   ------->setup_class
   ------->test_a #只执行了函数test_a
   .
   ------->teardown_class
       s # 跳过函数```


6.2 标记为预期失败函数

标记测试函数为失败函数
 方法:
     xfail(condition=None, reason=None, raises=None, run=True, strict=False)
 常用参数:
     condition:预期失败的条件,必传参数
     reason:失败的原因,必传参数
 使用方法:
     @pytest.mark.xfail(condition, reason="xx")

示例:

import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
        print("------->teardown_class")
    def test_a(self):
        print("------->test_a")
        assert 1
    @pytest.mark.xfail(2 > 1, reason="标注为预期失败") # 标记为预期失败函数test_b
       def test_b(self):
           print("------->test_b")
          assert 0
   执行结果:
       test_abc.py 
       ------->setup_class
       ------->test_a
       .
       ------->test_b
       ------->teardown_class
       x  # 失败标记

6.3 函数数据参数化

方便测试函数对测试属于的获取。
 方法:
     parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
 常用参数:
     argnames:参数名
     argvalues:参数对应值,类型必须为list
                 当参数为一个时格式:[value]
                 当参数个数大于一个时,格式为:[(param_value1,param_value2.....),(param_value1,param_value2.....)]
 使用方法:
     @pytest.mark.parametrize(argnames,argvalues)
     ️ 参数值为N个,测试方法就会运行N次
  

单个参数示例:

import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
        print("------->teardown_class")
@pytest.mark.parametrize("a",[3,6]) # a参数被赋予两个值,函数会运行两遍
def test_a(self,a): # 参数必须和parametrize里面的参数一致
    print("test data:a=%d"%a)
    assert a%3 == 0
    执行结果:
    test_abc.py 
    ------->setup_class
    test data:a=3 # 运行第一次取值a=3
    .
    test data:a=6 # 运行第二次取值a=6
    . 
    ------->teardown_class

多个参数示例:

import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
        print("------->teardown_class")
@pytest.mark.parametrize("a,b",[(1,2),(0,3)]) # 参数a,b均被赋予两个值,函数会运行两遍
def test_a(self,a,b): # 参数必须和parametrize里面的参数一致
    print("test data:a=%d,b=%d"%(a,b))
    assert a+b == 3
    执行结果:
    test_abc.py 
    ------->setup_class
    test data:a=1,b=2 # 运行第一次取值 a=1,b=2
    .
    test data:a=0,b=3 # 运行第二次取值 a=0,b=3
    .
    ------->teardown_class

函数返回值类型示例:

import pytest
def return_test_data():
    return [(1,2),(0,3)]
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")
    def teardown_class(self):
            print("------->teardown_class")
@pytest.mark.parametrize("a,b",return_test_data()) # 使用函数返回值的形式传入参数值
def test_a(self,a,b):
    print("test data:a=%d,b=%d"%(a,b))
    assert a+b == 3
    
    执行结果:
    test_abc.py 
    ------->setup_class
    test data:a=1,b=2 # 运行第一次取值 a=1,b=2
    .
    test data:a=0,b=3 # 运行第二次取值 a=0,b=3
    .
        ------->teardown_class

你可能感兴趣的:(Python_pytest详解)