当前位置:   article > 正文

自动化测试之Pytest测试框架_pytest web自动化

pytest web自动化

pytest是一个python的单元测试框架,可以用于自动化测试中。

官方文档:pytest: helps you write better programs — pytest documentation

特性

断言失败时提供详细信息
自动发现模块和方法
使用模块化的管理小的或者参数化长期存在的测试资源
可以运行unittes测试固件
python3.8以上
丰富的插件800+

安装pytest

pip install -U pytest

第一个测试

  1. # content of test_sample.py
  2. def func(x):
  3. return x + 1
  4. def test_answer():
  5. assert func(3) == 5

直接在命令行输入pytest即可运行 

或者运行时指定运行的测试文件

pytest -q test_sysexit.py

The -q/--quiet flag keeps the output brief in this and following examples.

 如何触发pytest测试

How to invoke pytest — pytest documentation

在模块中运行测试

pytest test_mod.py

在目录中运行测试

pytest testing/

按关键字表达式运行测试

pytest -k 'MyClass and not method'

按标记表达式运行测试

pytest -m slow

用例规则

pytest命令执行测试时,如果我们不指定具体的文件,PyTest默认从当前路径及其所有子目录中搜索py源文件,所有名字以test_开头或者以_test结尾的python源文件(.py文件)被认为是测试模块源文件,不符合这个命名规则的文件会被忽略。

●测试类(class)命名:默认以“Test”开头。

对于Pytest框架代码,你可以不把测试用例放置到class中,而是直接定义函数

测试固件

函数中的测试固件

●setup_module、teardown_module,在整个文件的开始和最后执行一次。

●setup_function和teardown_function,在每个函数开始前后执行。 

  1. import pytest
  2. '''
  3. 在函数中使用
  4. 1.setup_module、teardown_module,在整个文件的开始和最后执行一次
  5. 2.setup_function和teardown_function,在每个函数开始前后执行
  6. '''
  7. def setup_module():
  8. print('setup_module')
  9. def teardown_module():
  10. print('teardown_module')
  11. def setup_function():
  12. print('setup_function')
  13. def teardown_function():
  14. print('teardown_function')
  15. def test_a():
  16. print('aaaa')
  17. assert 'a' == 'a'
  18. def test_b():
  19. print('bbbb')
  20. assert 'b' == 'b'
  21. if __name__ == '__main__':
  22. pytest.main(["-s", "test_string_process.py"])
'
运行

 输出

test_string_process.py setup_module
setup_function
aaaa
.teardown_function
setup_function
bbbb
.teardown_function
teardown_module
 

(2)class中的测试固件

●setup_class、teardown_class,在整个class的开始和最后执行一次。

●setup_method和teardown_method,在每个方法开始前后执行。 

  1. import pytest
  2. '''
  3. 在class中使用
  4. 1.setup_class、teardown_class,在整个class的开始和最后执行一次
  5. 2.setup_method和teardown_method,在每个方法开始前后执行
  6. '''
  7. class Test01():
  8. def setup_class(self):
  9. print('setup_class')
  10. def teardown_class(self):
  11. print('teardown_class')
  12. def setup_method(self):
  13. print('setup_method')
  14. def teardown_method(self):
  15. print('teardown_method')
  16. def test_a(self):
  17. print('aaaa')
  18. assert 'a' == 'a'
  19. def test_b(self):
  20. print('bbbb')
  21. assert 'b' == 'b'
  22. if __name__ == '__main__':
  23. pytest.main(["-s", "./test_11_4.py"])

输出

test_string_process.py setup_class
setup_method
aaaa
.teardown_method
setup_method
bbbb
.teardown_method
teardown_class


============================== 2 passed in 0.02s ==============================

(3)setup和teardown

setup和teardown既可以应用在函数中,也可以应用在class中,作用对象是函数或方法。 

  1. import pytest
  2. def setup_module():
  3. print('setup_module')
  4. def teardown_module():
  5. print('teardown_module')
  6. def setup():
  7. print('setup')
  8. def teardown():
  9. print('teardown')
  10. def test_a():
  11. print('aaaa')
  12. assert 'a' == 'a'
  13. def test_b():
  14. print('bbbb')
  15. assert 'b' == 'b'
  16. if __name__ == '__main__':
  17. pytest.main(["-s", "./test_11_5.py"])

 输出

test_string_process.py setup_module
setup
aaaa
.teardown
setup
bbbb
.teardown
teardown_module

断言

如何在测试中编写和报告断言 — pytest 文档

断言(assert)并不是PyTest框架的功能特性,而是Python的内置语言特性,用于检查指定的表达式的结果是否为True。

PyTest使用assert来表达正确的测试逻辑期望。一个测试用例可以写多个断言,当有一个断言失败时,PyTest就认为测试的结果为失败,该测试用例的执行会被终止。

  1. import pytest
  2. '''
  3. pytest的断言更灵活
  4. '''
  5. class Test01():
  6. def setup_class(self):
  7. print('setup_class')
  8. def teardown_class(self):
  9. print('teardown_class')
  10. def setup_method(self):
  11. print('setup_method')
  12. def teardown_method(self):
  13. print('teardown_method')
  14. def test_a(self):
  15. print('aaaa')
  16. assert 5 > 3 # Python比较运算符
  17. def test_b(self):
  18. print('bbbb')
  19. assert 'Storm' in 'Hello Storm' # 成员运算符
  20. if __name__ == '__main__':
  21. pytest.main(["-s", "./test_11_8.py"])

测试执行

main函数

(1)执行同级和下级目录所有符合条件的测试使用pytest.main(["-s"])执行当前文件所在目录下所有符合条件的测试用例

  1. import pytest
  2. def test_b():
  3. print('bbbb')
  4. assert 'Storm' in 'Hello Storm'
  5. if __name__ == '__main__':
  6. pytest.main(["-s"])

 .-s参数,关闭捕捉,输出信息。使用-v参数则不会在控制台输出信息。

(2)pytest.main(["-s", "test_11_10.py"])

在调试脚本的时候,如果我们希望脚本只执行当前文件,那么可以直接传递文件参数名

(3)pytest.main(["-s", "./test_11_11.py::Test02"])

在class风格的脚本中,调试的时候还可以通过在文件名后加两个冒号和class名来指定执行某个class。

命令窗口执行

(1)执行当前目录所有测试用例首先进入目标目录,然后直接执行“pytest”即可自动寻找当前目录下的测试用例

(2)执行指定的用例文件“pytest+文件名”用来执行指定用例文件

 (3)执行指定的用例类我们可以通过“文件名+::+类名”的方式来执行指定的用例类

失败重跑

Pytest本身不支持测试用例执行失败重试的功能。我们需要安装一个插件——pytest rerunfailures。然后就可以通过“--reruns重试次数”来设置测试用例执行失败后的重试次数。

 在命令行使用

pytest test_11_12.py --reruns 2 ---reruns-delay 2

表示重试两次,时间间隔为2秒

标记机制

Pytest提供了标记机制,借助“mark”关键字,我们可以对测试函数(类、方法)进行标记。

对测试用例进行分级,例如某些主流程的用例可以标记为L1,次要流程的用例标记为L2等。这样有一个好处,我们可以在不同的情况执行不同的测试用例,例如,在做冒烟测试的时候,只需要执行L1级别的用例就行了。

●一个测试函数(类、方法)可以有多个标记。

●一个标记也可以应用于多个函数(类、方法)。

●执行参数使用:pytest -m mark名。

●执行多个标记:pytest -m "L1 or L2"。

  1. import pytest
  2. class Test01():
  3. @pytest.mark.L1
  4. @pytest.mark.L2
  5. def test_a(self):
  6. print('aaaa')
  7. assert 'a' == 'a'
  8. @pytest.mark.L2
  9. def test_b(self):
  10. print('bbbb')
  11. assert 'b' == 'b'
  12. class Test02():
  13. @pytest.mark.L1
  14. def test_c(self):
  15. print('cccc')
  16. assert 'c' == 'c'
  17. @pytest.mark.L3
  18. def test_d(self):
  19. print('dddd')
  20. assert 'd' == 'd'

只执行L1级别

pytest -s "test_string_process.py" -m "L1"
 

执行L1和L2

pytest -s "test_string_process.py" -m "L1 or L2" 

执行非L1

pytest -s "test_string_process.py" -m "not L1" 

跳过用例

(1)使用skip(reason=None)实现无条件跳过 

  1. import pytest
  2. class Test01():
  3. @pytest.mark.skip(reason='这里是原因')
  4. def test_a(self):
  5. print('aaaa')
  6. assert 'a' == 'a'
  7. def test_b(self):
  8. print('bbbb')
  9. assert 'b' == 'b'
  10. if __name__ == '__main__':
  11. pytest.main(["-s", "./test_11_14.py"])
'
运行

(2)使用skipif(condition, reason=None)实现满足条件跳过 

  1. import pytest
  2. class Test01():
  3. @pytest.mark.skipif(2>1, reason='这里是原因')
  4. def test_a(self):
  5. print('aaaa')
  6. assert 'a' == 'a'
  7. def test_b(self):
  8. print('bbbb')
  9. assert 'b' == 'b'
  10. if __name__ == '__main__':
  11. pytest.main(["-s", "./test_11_14.py"])
'
运行

 全局设置

前面我们介绍的配置信息要么是在文件的main方法中,要么是在命令行。这里我们还可以在测试目录下面创建一个pytest.ini文件,文件中可以设定一些执行规则,借助该文件可以修改Pytest的默认行为,即可以修改Pytest的执行规则。

然后,我们就可以将一些配置信息写入pytest.ini文件。这里需要注意以下3点。

●文件名必须是pytest.ini。

●文件内容必须以“[pytest]”开头。

●文件内容不能包含中文。

 通过关键字“addopts”来设置命令行参数,如“-s”或“-v”监控、失败重试的次数、重试的时间间隔、按标签来执行,多个参数之间用空格分隔

将自定义标签添加到pytest.ini文件中。

自定义测试用例查找规则

●在当前文件目录中的testcases目录下查找测试用例:testpaths = testcases。

●查找文件名以“test_”开头的文件,也可以修改为以其他文件名开头:python_file =test_*.py。

●查找以“Test*”开头的类,也可以修改为以其他类名开头:python_classes =Test*。

●查找以“test_”开头的函数,也可以修改为以其他函数名开头:python_functions = test_*。

  1. [pytest]
  2. addopts = -v --reruns 2 --reruns-delay 2 -m "L1"
  3. markers = L1:level_1 testcases
  4. L2:level_2 testcases
  5. testpaths = testcases
  6. python_file = test_*.py
  7. python_classes = Test*
  8. python_functions = test_*
'
运行

 注意需要进入testcases文件夹的终端命令行输入pytest,既可以按照配置文件执行用例。

合理使用pytest.ini文件能方便地控制测试用例执行的情况。

测试报告

Pytest框架支持多种形式的测试报告。将分别介绍pytest-html和Allure两种测试报告

pytest-html

安装,安装好以后,我们只需要在执行“pytest”命令的时候指定--html参数。

pip install pytest-html 

pytest --html=report.html 

生成的html文件打开即为报告。 

  1. import pytest
  2. class TestStorm1(object):
  3. @pytest.mark.L1
  4. def test_01(self):
  5. print('aaa')
  6. assert 'a'=='a'
  7. if __name__ == '__main__':
  8. pytest.main(["-s", "test_storm_1.py", "--html=./report.html"])
'
运行

也可以将测试报告的配置项放到pytest.ini文件

allure测试报告

Allure基于Java开发,因此我们需要提前安装Java 8或以上版本的环境。

◆安装allure-pytest插件在DOS窗口输入命令“pip3 install allure-pytest”,然后按“Enter”键。

下载安装Allure:你可以从GitHub下载安装文件“allure2-2.13.3.zip”,解压后,将bin目录配置到环境变量中,然后在DOS窗口中输入“allure”,并按“Enter”键,如果显示“Usage”的话,说明设置成功。

使用如下命令执行:pytest.main(["-m","login","-s","-q","--alluredir=./report"])。

●“-m”:标记用例。

●“login”:被标记需要执行用例。

●“-s”:允许终端在测试执行时输出某些结果,例如你想输入print的内容,可以加上“-s”。

●“-q”:简化输出结果。

●“--alluredir”:生成Allure指定语法。

●“./report”:生成报告的目录。

●“--clean-alluredir”:因为这个插件库allure-pytest生成了报告文件,你第二次执行时不会清理掉里面的东西,所以你需要删除这个report文件夹,然后执行重新新建report文件夹命令。说明:命令执行后,程序会在report文件夹里面生成文件。 

定制报告

●feature:标注主要功能模块。

●story:标注features功能模块下的分支功能。

●severity:标注测试用例的重要级别。

blocker级别:致命缺陷。critical级别:严重缺陷。normal级别:一般缺陷,默认为这个级别。minor级别:次要缺陷。trivial级别:轻微缺陷。

●step:标注测试用例的重要步骤。

●attach:用于向测试报告中输入一些附加的信息,通常是一些测试数据信息。

●name就是附件名称,body就是数据,attachment_type就是传类型。附件支持的类型有TEXT、HTML、XML、PNG、JPG、JSON、OTHER。

●issue:这里传的是一个连接,记录的是你的问题。

●testcase:这里传的是一个连接,记录的是你的用例。

●description:描述用例信息。

  1. import pytest,allure
  2. @allure.feature("测试场景1") #标记场景
  3. class TestDemo():
  4. @allure.story("测试用例1-1") # 标记测试用例
  5. @allure.severity("trivial") # 标记用例级别
  6. def test_1_1(self): # 用例1
  7. a = 1 + 1
  8. assert a == 2
  9. @allure.story("测试用例1-2")
  10. @allure.severity("critical")
  11. @allure.step('用例2:重要步骤')
  12. def test_1_2(self):
  13. assert 2 == 2
'
运行

通过main来执行测试用例,这时候程序会在report文件夹中生成一些JSON格式的文件

接下来回到DOS窗口,执行“allure generate --clean report”命令,可以看到新生成了一个allure-report文件夹,可以用浏览器打开index.html文件了

 ●区域一:显示报告生成的时间,执行的时间,一共执行了多少个测试用例,环状图显示用例通过的比例。

●区域二:显示的是测试集合(class)情况。

●区域三:显示的是测试场景(@allure.feature)。

●区域四:显示失败用例的信息。

Pytest参数化

Pytest自身支持参数化,使用方法为@pytest.mark.parametrize("argnames",argvalues)。●argnames:参数名称,单个参数用参数名,多个参数可以拼接到一个元组中。

●argvalues:参数对应值,类型必须为可迭代类型,一般为列表。

  1. from selenium import webdriver
  2. import pytest
  3. data = [('admin', 'error', '0'), ('admin', 'rootroot', '1')]
  4. @pytest.mark.parametrize(("username", "password", "status"), data)
  5. class TestLogin():
  6. def setup(self):
  7. self.driver = webdriver.Chrome()
  8. self.driver.maximize_window()
  9. self.driver.implicitly_wait(20)
  10. # 访问"登录"页面
  11. self.driver.get('http://localhost:81/redmine/login')
  12. def teardown(self):
  13. self.driver.quit()
  14. def test_001_login(self, username, password, status):
  15. # 登录名
  16. login_name = self.driver.find_element_by_id('username')
  17. login_name.clear()
  18. login_name.send_keys(username)
  19. # 登录密码
  20. login_pwd = self.driver.find_element_by_id('password')
  21. login_pwd.clear()
  22. login_pwd.send_keys(password)
  23. # "登录"按钮
  24. login_btn = self.driver.find_element_by_id('login-submit')
  25. login_btn.click()
  26. if status == '0':
  27. # 登录失败后的提示信息
  28. ele = self.driver.find_element_by_id('flash_error')
  29. assert '无效的用户名或密码' in self.driver.page_source
  30. elif status == '1':
  31. # 登录后显示的用户名
  32. name = self.driver.find_element_by_link_text(username)
  33. assert name.text == username
  34. else:
  35. print('参数化的状态只能传入0或1')
  36. if __name__ == '__main__':
  37. pytest.main(['-s', '-q', '--alluredir', './report/'])
'
运行

并发运行测试用例集

当你的测试用例比较多时,最好可以通过并发测试来减少测试整体的运行时间。pytest 支持并发测试,并且有不同的并发测试库,其中如下两个比较著名:

  • pytest-parallel

  • pip install pytest-parallel

运行:使用 pytest-parallel 运行,需要指定参数。

–workers (optional)  X

多进程运行, X 是进程数,默认值 1。

–tests-per-worker (optional)   X

多线程运行, X 是每个 worker 运行的最大并发线程数, 默认值1。

注意:这个插件仅仅支持 python 3.6 版本及以上,而且如果你想多进程并发,必须跑在 Unix 或者 Mac 机器上,windows 环境仅仅支持多线程运行。

  1. pytest --workers 2 #指定2个进程并发

  2. #指定2个进程并发,每个进程最多运行3个线程

  3. pytest --workers 2 --test-per-worker 3

固件fixture 

Fixture可以看作是一种特殊的函数,它可以在测试用例执行前后执行一些预设或清理的操作。它常用于设置和清理测试环境,例如创建和删除临时文件、启动和关闭服务器等。

https://blog.csdn.net/seanyang_/article/details/128957344

如何使用夹具 — pytest 文档 

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

闽ICP备14008679号