• 初识Pytest自动化测试框架,我彻底懂了


    初识Pytest

    • Pytest是Python实现的一个测试工具,可以用于所有类型和级别的软件测试

    • Pytest是一个可以自动查找到你编写的用例并运行后输出结果的测试框架

    • Pytest的特点:

      • 是一个命令行工具,编写用例简单,可读性强
      • 非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考
      • 支持单元测试和功能测试
      • 支持参数化
      • 执行测试过程中可以将某些测试跳过,或者对某些预期失败的Case标记成失败
      • 支持重复执行失败的Case
      • 支持运行由unittest编写的测试Case
      • 具有很多第三方插件,并且可以自定义扩展
      • 方便的和持续集成工具集成
      • 可以运行以test开头或test结尾的包、文件和方法
      • 可以使用assert进行断言
    • Pytest 安装

       pip install -U pytest -i https://pypi.tuna.tsinghua.edu.cn/simple
      

    Pytest 第一个例子

    • pytest 默认能够自动识别 test 开头函数和方法,以及 Test 开头的类。
    1. import pytest
    2. import requests
    3. def test_one():
    4. r = requests.get('https://www.baidu.com')
    5. print(r.status_code)
    6. def test_two():
    7. r = requests.get('https://www.baidu.com')
    8. print(r.encoding)
    9. class TestTask(object):
    10. def test_1(self):
    11. print('test 1')
    12. def test_2(self):
    13. print('test 2')
    14. if __name__ == '__main__':
    15. pytest.main() # pytest
    • 右键直接运行,结果如下
    1. ============================= test session starts ==============================
    2. platform darwin -- Python 3.7.3, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
    3. rootdir: /Users/xiaoyidemac/Desktop/测试
    4. plugins: tavern-1.16.3, openfiles-0.3.2, arraydiff-0.3, allure-pytest-2.9.45, doctestplus-0.3.0, remotedata-0.3.1collected 4 items
    5. pytest_code.py .200
    6. .ISO-8859-1
    7. [100%]
    8. ============================== 4 passed in 0.29s ===============================
    9. Process finished with exit code 0
    10. .test 1
    11. .test 2

    pytest运行方式

    通过代码中pytest.main()可以右键直接运行,相当于python test_1.py;也可以通过命令行的方式启动运行

    代码中运行的方式

    • pytest.main()
      会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
      pytest先获取所有文件中的测试函数后,再执行
      不会显示代码中的标准输出(print、logging)
    • pytest.main(['-s'])
      会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
      pytest先获取所有文件中的测试函数后,再执行
      显示代码中的标准输出(print、logging)
    • pytest.main(['test_1.py'])
      只会执行当前文件
      不会显示代码中的标准输出(print、logging)
    • pytest.main(['-s', 'test_1.py'])
      只会执行当前文件
      显示代码中的标准输出(print、logging)

    上述四种方式皆有对应的命令行运行的方式

    • pytest
      会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
      pytest先获取所有文件中的测试函数后,再执行
      不会显示代码中的标准输出(print、logging)
    • pytest -s
      会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
      pytest先获取所有文件中的测试函数后,再执行
      显示代码中的标准输出(print、logging)
    • pytest test_1.py
      只会执行当前文件
      不会显示代码中的标准输出(print、logging)
    • pytest -s test_1.py
      只会执行当前文件
      显示代码中的标准输出(print、logging)

    注意:

    • 测试脚本中的测试类,如果不以Test作为名称开头,将无法执行
    • 测试脚本中的函数,如果不以test作为名称开头,将无法执行

    断言的处理

    assert

    什么是断言

    • 断言就是用来检测程序是否正确, 若条件为假,就中断程序执行
    • 编写代码时,总是会做出一些假设,断言就是用于在代码中捕捉这些假设
    • 断言表示为一些布尔表达式

    断言的使用场景

    • 使用assert语句
    • 断言预期的异常
    • 断言预期的警告

    assert断言语句

    • 采用assert断言时,可添加备注信息
    • 当断言预测失败时,备注信息会以AssertionError抛出,并在控制台输出
    1. assert expression [, arguments]
    2. # expression 为 True 则 pass
    3. # expression 为 False 则 抛出异常,有 argument 则输出 argument
    4. '''
    5. expression:
    6. 1)比较运算
    7. 2)逻辑运算  and | or | not
    8. 3)身份运算  is | is not
    9. 4)成员运算  in | not in
    10. '''

    示例代码:

    1. import requests
    2. def test_assert():
    3. r = requests.get('http://www.baidu.com')
    4. assert r.status_code == 200, "没有返回200,断言失败"

    异常断言

    • 在测试过程中,对某些方法进行测试时,预测输入某些特定数据,会抛出某种异常,若出现该异常,则用例执行通过。

    • 对这预期会出现的异常的断言,可以采用pytest中的pytest.raises()进行处理。

    pytest.raises()的使用

    • pytest.raises(expected_exception, match=None, kwargs)
      expected_exception 是预期异常类或者的异常类元组
      match 用于匹配异常的消息内容
    1. import pytest
    2. def is_leap_year(year):
    3. # 先判断year是不是整型
    4. if isinstance(year, int) is not True:
    5. raise TypeError("传入的参数不是整数")
    6. elif year == 0:
    7. raise ValueError("公元元年是从公元一年开始!!")
    8. elif abs(year) != year:
    9. raise ValueError("传入的参数不是正整数")
    10. elif (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
    11. print("%d年是闰年" % year)
    12. return True
    13. else:
    14. print("%d年不是闰年" % year)
    15. return False
    16. class TestAssert(object):
    17. """对判断是否是闰年的方法进行测试"""
    18. def test_exception_typeerror(self):
    19. # 使用 pytest.raises 作为上下文管理器,捕获给定异常类型TypeError
    20. # is_leap_year('2020')抛出TypeError,被pytest.raises捕获到,则测试用例执行通过
    21. with pytest.raises(TypeError):
    22. # 传入字符串引发类型错误
    23. is_leap_year('2020')

    运行结果如下:

    1. ============================= test session starts ==============================
    2. platform darwin -- Python 3.7.3, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
    3. rootdir: /Users/xiaoyidemac/Desktop/测试
    4. plugins: tavern-1.16.3, openfiles-0.3.2, arraydiff-0.3, allure-pytest-2.9.45, doctestplus-0.3.0, remotedata-0.3.1collected 1 item
    5. pytest_code.py [100%]
    6. ============================== 1 passed in 0.06s ===============================

    把异常信息存储到变量

    有时候我们可能需要在测试用到产生的异常信息,我们可以把异常信息存储到一个变量中,变量的类型为 异常类 ,包含异常的 type、value 或者 traceback 等信息。

    1. import pytest
    2. def is_leap_year(year):
    3. # 先判断year是不是整型
    4. if isinstance(year, int) is not True:
    5. raise TypeError("传入的参数不是整数")
    6. elif year == 0:
    7. raise ValueError("公元元年是从公元一年开始!!")
    8. elif abs(year) != year:
    9. raise ValueError("传入的参数不是正整数")
    10. elif (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
    11. print("%d年是闰年" % year)
    12. return True
    13. else:
    14. print("%d年不是闰年" % year)
    15. return False
    16. class TestAssert(object):
    17. """对判断是否是闰年的方法进行测试"""
    18. def test_exception_typeerror(self):
    19. # 预测到参数不符合要求,会抛出TypeError异常;若出现该异常,则测试用例执行通过
    20. with pytest.raises(TypeError) as err_info:
    21. # 传入字符串引发类型错误
    22. is_leap_year('2020')
    23. # 断言异常的类型是 TypeError,断言成功则不会抛出异常
    24. assert err_info.type == TypeError, '错误类型不匹配'

    通过异常的内容捕捉异常

    1. import pytest
    2. def is_leap_year(year):
    3. # 先判断year是不是整型
    4. if isinstance(year, int) is not True:
    5. raise TypeError("传入的参数不是整数")
    6. elif year == 0:
    7. raise ValueError("公元元年是从公元一年开始!!")
    8. elif abs(year) != year:
    9. raise ValueError("传入的参数不是正整数")
    10. elif (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
    11. print("%d年是闰年" % year)
    12. return True
    13. else:
    14. print("%d年不是闰年" % year)
    15. return False
    16. class TestAssert(object):
    17. """对判断是否是闰年的方法进行测试"""
    18. def test_exception_typeerror(self):
    19. # 通过异常的内容捕捉异常,但具体是何种异常不清楚
    20. with pytest.raises(Exception, match='从公元一年开始') as err_info:
    21. is_leap_year(0)
    22. # 断言异常的类型是 ValueError,断言成功则不会抛出异常
    23. assert err_info.type == ValueError

    警告断言

    • pytest 中对警告进行断言采用 pytest.warns() 方法,其断言的方法与 pytest.raises() 类似。
    • pytest.warns() 除了能断言告警外,还能够捕获告警信息,并对捕获的告警信息进行分类处理,可以设定出现特定告警信息时,则用例执行失败。
    • 程序中抛出警告时,并不会中断程序的执行,一般是打印警告信息,而程序抛出异常时可能直接中断程序的运行。因此对于警告类信息我们在捕获的时候,可以捕获到多个,而异常信息只能捕获到一个。

    pytest.warns()的使用

    • pytest.warns(expected_warning, *args, match, **kwargs)
      --- expected_warning 预期的警告类或者警告类元组,例如:
      DeprecationWarning 弃用警告
      UserWarning 用户警告
    • match 可以自定义的匹配警告内容
    1. import pytest
    2. import warnings
    3. def make_warn():
    4. # 抛出
    5. warnings.warn("deprecated", DeprecationWarning)
    6. def not_warn():
    7. pass
    8. def user_warn():
    9. warnings.warn("user warn", UserWarning)
    10. class TestWarns(object):
    11. def test_make_warn(self):
    12. with pytest.warns(DeprecationWarning):
    13. make_warn()
    14. def test_not_warn(self):
    15. # 断言not_warn函数将会抛出警告
    16. # 但实际是没有抛出警告的,所以无法通过测试
    17. with pytest.warns(Warning):
    18. not_warn()
    19. def test_user_warn(self):
    20. with pytest.warns(UserWarning):
    21. user_warn()

    运行结果如下:

    1. ================================================== test session starts ===================================================
    2. platform linux -- Python 3.6.8, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
    3. rootdir: /home/python/code/unit_testing/pytest_code
    4. collected 3 items
    5. test_7.py .F. [100%]
    6. ======================================================== FAILURES ========================================================
    7. ________________________________________________ TestWarns.test_not_warn _________________________________________________
    8. self =
    9. def test_not_warn(self):
    10. with pytest.warns(Warning):
    11. > not_warn()
    12. E Failed: DID NOT WARN. No warnings of type (,) was emitted. The list of emitted warnings is: [].
    13. test_7.py:24: Failed
    14. ================================================ short test summary info =================================================
    15. FAILED test_7.py::TestWarns::test_not_warn - Failed: DID NOT WARN. No warnings of type (,) was emitted...
    16. ============================================== 1 failed, 2 passed in 0.04s ===============================================

    把警告信息存储到变量

    将告警信息存入一个变量中,通过读取这个变量中的信息进行断言,包括:告警的个数、告警信息参数等。

    1. # pytest_code/test_8.py
    2. import warnings
    3. import pytest
    4. def warn_message():
    5. warnings.warn("user", UserWarning)
    6. warnings.warn("runtime", RuntimeWarning)
    7. def test_warn_match():
    8. with pytest.warns((UserWarning, RuntimeWarning)) as record:
    9. warn_message()
    10. assert len(record) == 2
    11. assert str(record[0].message) == "user"
    12. assert str(record[1].message) == "runtime"
    13. assert record[0].category == UserWarning
    14. assert record[1].category == RuntimeWarning

    运行结果如下:

    1. $ pytest test_8.py
    2. ================================================== test session starts ===================================================
    3. platform linux -- Python 3.6.8, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
    4. rootdir: /home/python/code/unit_testing/pytest_code
    5. collected 1 item
    6. test_8.py . [100%]
    7. =================================================== 1 passed in 0.01s ====================================================

    通过警告的内容捕捉警告

    1. # pytest_code/test_9.py
    2. import warnings
    3. import pytest
    4. def make_warn():
    5. # 抛出
    6. warnings.warn("deprecated", DeprecationWarning)
    7. def not_warn():
    8. pass
    9. def user_warn():
    10. warnings.warn("user warn", UserWarning)
    11. class TestWarns(object):
    12. def test_make_warn(self):
    13. # 捕获警告内容为deprecated的警告
    14. with pytest.warns(Warning, match='deprecated'):
    15. make_warn()

      最后我这里给你们分享一下我所积累和真理的文档和学习资料有需要是领取就可以了

    1、学习思路和方法

    这个大纲涵盖了目前市面上企业百分之99的技术,这个大纲很详细的写了你该学习什么内容,企业会用到什么内容。总共十个专题足够你学习

    2、想学习却无从下手,该如何学习?

    这里我准备了对应上面的每个知识点的学习资料、可以自学神器,已经项目练手。

    3、软件测试/自动化测试【全家桶装】学习中的工具、安装包、插件....

     4、有了安装包和学习资料,没有项目实战怎么办,我这里都已经准备好了往下看

     最后送上一句话:

    世界的模样取决于你凝视它的目光,自己的价值取决于你的追求和心态,一切美好的愿望,不在等待中拥有,而是在奋斗中争取。

    如果我的博客

    对你有帮助、如果你喜欢我的文章内容,请 “点赞” “评论” “收藏” 一键三连哦!

  • 相关阅读:
    “index“ should always be multi-word
    Games104现代游戏引擎入门-lecture12游戏引擎的粒子和声效系统
    Wi-SUN归来,信驰达携手TI发力广域自组网
    葡萄糖-聚乙二醇-链霉亲和素|Streptavidins-PEG-Glucose|链霉亲和素-PEG-葡萄糖
    Django REST项目实战:在线中文字符识别
    SpringBoot+vue开发记录(二)
    gpio模拟spi读写寄存器示例代码
    初次接触Sharding-JDBC并实际应用
    沉睡者IT - 什么是Web3.0?
    【Netty】Netty 编码器(十三)
  • 原文地址:https://blog.csdn.net/Liuyanan990830/article/details/128087661