一文读懂Python之pytest

pytest官网:https://docs.pytest.org/en/stable/

pytest和unittest都是python的测试框架,但是pytest相比于unittest,又有以下特点:

  • 增加了标记功能
  • 有丰富的插件库,目前有800+ (点击跳转插件地址
  • 增加了fixture(可以设置会话级、模块级、类级、函数级的fixture)
  • 自动发现测试模块和测试方法
  • 断言方式为 assert 表达式 即可。(更加自由,表达式可以有逻辑运算可以是函数返回值)

【备注】

会话级:整个自动化用例运行过程中只执行一次的事情

模块级:每个py文件

类级:例如unittest中setUpClass和tearDownClass完成的事情

函数级:即用例级别,例如unittest中setUp和tearDown完成的事情

pytest安装

1、安装(-U即--upgrade,意思是如果已安装,则升级到最新版)

pip install -U pytest

2、检查安装是否成功

$ pytest --version
pytest 6.1.2

 

pytest自动收集测试用例的规则

1、在哪个目录下运行pytest命令,则在那个目录下搜索测试用例

2、test_*.py文件 或者 *_test.py 文件中:

(1)以test_*开头的函数名

(2)以Test开头的测试类(不能有__init__函数)中,以test_*开头的函数

上述(1)(2)是或的关系。因为py文件中可以直接写函数,或者先写类,再在类中写函数。

为什么类不能有__init__函数:

__init__是一个类的构造函数,但是为什么不能有它我也不知道。但是有的话,确实会报错。

pytest标记

在测试用例/测试类前面加上: @pytest.mark.标记名

可以在一个用例上面加多个标记。标记名可以自己取。

@pytest.mark.main  #该类下的所有用例都有该标记
class TestLogin:

  @pytest.mark.demo   @pytest.mark.smoke
  @pytest.mark.skip
  def test_login_success():     pass
  def test_login_success():
    pass

需要运行的目录下添加pytest.ini配置文件,在其中给标记注册。如下:

[pytest]
markers =
    smoke: smoke case
    skip: skip case

 

pytest命令

$ pytest  #直接收集用例并执行
$ pytest --help  #帮助
$ pytest -m smoke  #仅执行标记了smoke的测试用例

 执行命令:

-q  :更简洁的报告模式。Execute the test function with “quiet” reporting mode。

-v  :更详细的报告模式;

-m :仅执行满足mark表达式的测试用例。only run tests matching given mark expression。示例:pytest -m 'mark1 and not mark2'.

 

pytest之fixture

fixture:即测试用例执行的环境准备和清理;在unittest中体现为:setUp/tearDown/setUpClass/tearDownClass;

fixture主要的目的是为了提供一种手段去执行重复的、基本的内容。

例如:测试某个电商网站的功能,登录和退出就可以用到fixture,几乎每个用例都需要登录和退出。

 

定义fixture:在函数声明前加上标记  @pytest.fixture   在函数内部通过yield关键字分割环境准备和清理。

可选范围:function(默认), class, module, package, session

@pytest.mark.usefixtures('') 可以叠放使用,但是先执行底层的,再执行上层的。下面的例子中先执行reresh_page,再执行login;

 

conftest.py文件专门用来写公用的fixture,不需要引用,直接用标记即可使用。(必须和test_*.py在一个层级,或位于它的父级)

conftest可以按路径写多个。使用时有就近原则。

 1 driver = None
 2 @pytest.fixture(scope='class')
 3 def login():
 4     #前置
 5     global driver
 6     driver = webdriver.Chrome()
 7     lg = ...
 8     yield (lg,driver)  #分割线 + 返回值
 9     #后置
10 
11 
12 @pytest.fixture(scope='function')  
13 # 默认就是函数级别。也可以简写成:@pytest.fixture
14 # scope:"function"(default), "class", "module", "package" or "session"
15 def reresh_page():
16     global driver
17     yield    #分割线
18     driver.refresh()
View Code
 1 #使用fixtures。
 2 #作用域不一样login只会执行一次,reresh_page执行次数和用例一样。
 3 @pytest.mark.usefixtures("login")
 4 @pytest.mark.usefixtures("reresh_page")
 5 class TestLoging:
 6     
 7     def test_login_success(self,login): #fixture的函数名称,用来接收它的返回值
 8           login[1].find_element...
 9           ...
10 
11     def test_error_pwd(self,login):
12           pass
View Code

 

pytest之断言

直接使用assert 。不再使用unittest的self.assertTrue()之类的方法。

1 #self.assertTrue(IndexPage(self.driver).is_exit_exist())
2 #pytest直接用assert.
3 #assert后面的值要么是True要么是False
4 #assert后面的值还可以参与逻辑运算,可以是函数返回值
5 assert IndexPage(self.driver).is_exit_exist()
View Code

 

pytest之ddt的实现

使用方法:@pytest.mark.parametrize('参数名',列表数据)
#参数名:用来接收每一项数据,并且作为测试用例的参数
#列表数据:一组数据

@pytest.mark.parametrize("p_data",LD.phone)
def login(p_data): #函数名称中必须当成参数传递过来
    pass

 

pytest之插件

1、重运行机制:pytest-rerunfailures

#安装
pip install pytest-rerunfailures
#使用
$ pytest --reruns 5 --reruns-delay 1
--reruns 重运行次数
--reruns-delay 上一次执行完后等待多久再次重运行。单位:秒

2、html测试报告:pytest-html

#安装
pip install pytest-html
#使用 只能配置相对路径
$ pytest --html=report\\report.html

3、html测试报告:pytest-testreport

#安装
pip install pytest-testreport

#使用-可配置参数template指模板(1、2)
pytest --report=report.html --title=测试报告 --tester=testername --desc=项目描述 --template=1

#若使用时报错,No module named 'jinja2',则需安装
pip install jinja2

拓展:

pytest自带的报告:--junit-xml = report.xml (可以通过pytest --help命令看见) 可以集成到jenkins

 

报错及解决方案

使用pytest的报错记录

1、

[9580:13912:0618/213000.930:ERROR:device_event_log_impl.cc(214)] [21:30:00.929] Bluetooth: bluetooth_adapter_winrt.cc:1074 Getting Defau
lt Adapter failed.

处理方案:需要加上options

options  = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-logging"])
services = Service(executable_path=getpath.chromedriver_path)
driver = webdriver.Chrome(options=options,service=services)

2、 TypeError: 'TestIndex' object is not subscriptable

处理方案:写测试类时,类方法第一个参数代表自己,必须是self,后面才是从fixture接收的参数;

3、


posted @ 2021-01-09 19:47  youreyebows  阅读(743)  评论(0编辑  收藏  举报