python之pytest

这篇具有很好参考价值的文章主要介绍了python之pytest。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、介绍

pytest是python的一种单元测试框架,同自带的unittest测试框架类似,相比起来,pytest更简单。

特点:
1.入门简单,文档丰富
2.支持简单的单元测试和复杂的功能测试
3.支持参数化
4.执行测试过程中可以将某些测试跳过,或者对某些预期失败的case标记成失败
5.支持重复执行失败的case
6.支持运行由Nose,unittest编写的case
7.具有多个第三方插件,还可以自定义扩展
8.方便和持续集成工具集成

编写规范:

  • 测试文件以test_开头或结尾
  • 测试类以Test开头,并且不能带有_ _ init _ _方法
  • 测试函数以test_开头

安装
pip install pytest

例子:

import pytest

def test_a():
    print('\ntesta 11111111111')
    assert 1

def test_b():
    print('\ntestb ttttttttt')
    assert 1

if __name__=='__main__':
    pytest.main('test_prac.py')

注意:
1、要先切换成pytest模式才能正常运行
2、包名、模块名都需要以test_开头才能正常执行
3、需要将打印模块开启才会将结果打印在输出栏,操作如下:pytest,python,pytest,单元测试

二、使用

1、setup 和teardown函数

setup和teardown函数主要分为模块级、类级、功能级、函数级别。这两个函数存在测试类的内部。
作用:在函数调用之前执行setup,在函数调用之后执行teardown

注意点:
1.类名一定要Test_开头,并且T要大写
2.在终端运行时,需要先切换到当前文件目录下。否则会报错找不到module
3.-s是输出程序运行信息。想要让setup、teardown在控制窗口打印,需要加-s 执行,如:pytest -s test_prac.py

适用场景:
比如登录,发送请求的请求头等等

函数级别

特点:
当是函数级别的时候,每执行一个函数,就会跟着执行一次setup和teardown

import pytest

#类名一定要Test_开头,并且T要大写,不然执行不了
class Test_abd():
    def setup(self):
        print('=====setup======')
    def teardown(self):
        print('=====teardown===')
    def test_a(self):
        print('\ntesta 11111111111')
        assert 1

    def test_b(self):
        print('\ntestb ttttttttt')
        assert 1
        
    def test_c(self):
        print('\ntestb ttttttttt')
        assert 1   

result:
pytest,python,pytest,单元测试

类级别

特点:在一个测试类,不管有多少方法,都只运行一次setup和teardown。相当于setup和teardown将其他方法包裹在内部执行。

import pytest

#类名一定要Test_开头,并且T要大写,不然执行不了
class Test_abd():
    # #类级别的使用:setup和teardown只执行一次
    def setup_class(self):
        print('=====setup======')
    def teardown_class(self):
        print('=====teardown===')
    def test_a(self):
        print('\ntesta 11111111111')
        assert 1

    def test_b(self):
        print('\ntestb ttttttttt')
        assert 1

result:
pytest,python,pytest,单元测试

2、 pytest配置文件

pytest配置文件通常放在测试目录下,名称为pytest.ini ,命令运行时,会使用该配置文件中的配置。配置完以下配置后,可直接在控制台输入pytest即可执行所有指定的文件内容。

#配置pytest命令行运行参数 ,多个参数用空号隔开
[pytest]
addopts=-s

以下几种路径也可以单独写,比如只写python_files,那么会在当前路径下查找所有的test_*.py文件

配置测试搜索的路径 ;
[pytest]
testpaths=./scripts
#寻找当前目录下的scripts里的文件,可自定义

#配置测试搜索的文件名
[pytest]
python_files=test_*.py
寻找当前目录下的scripts文件夹下,以test_开头,.py结尾的所有文件中

#配置测试搜索的测试类名
[pytest]
python_classes=Test_*
#当前目录下的scripts文件夹下,以test_开头,.py为结尾的文件中,以Test_开头的类

配置测试搜索的测试函数名
[pytest]
python_functions=test_*
#搜索当前目录下的scripts文件夹下,以test_开头,.py为结尾的文件中,以Test_开头的类里的以test_开头的方法

3、公共类编写

公共模块要在不同文件中,大家都要能访问到,所以一般是放在根目录下。

在pytest中使用conftest.py这个文件进行数据共享,并且放在不同得位置起着不同范围的共享作用。

比如登录函数需要共享使用,那么将登录模块带@pytest.fixture写在conftest.py中。系统执行参数login的时候,会先从本文件中查找是否有该名字的变量,之后再去conftest.py中查找。

一般pytest.fixture()会和conftest.py文件一起使用,它的名字是固定的,功能很强大:
1.conftest.py文件时单独存放pytest.fixture()的方法,用处时可以在多个py文件之间共享前置配置
2.conftest.py里面的方法在调用时不需要导入,直接使用
3.conftest.py可以有多个,也可以有多个不同层级

import pytest
import readYaml

@pytest.fixture(scope="function")
def conn_database():
    print('连接数据库')
    yield
    print("关闭数据库")

def clear_yaml():
    readYaml.readYaml.clear_yaml()

4、常用插件

4.1 自动输出测试报告插件

pytest-html 插件用来生成测试报告。方便简单。
安装pip install pytest-html

1、首先创建一个简单的测试类:

import pytest
class Test_report():
    def test_12(self):
        print('121212')
    def test_34(self):
            print('343434')

2、需要将该测试结果自动生成测试报告:
可以通过命令行直接生成:pytest -s pytest_report.py --html=./pytest_report.html

另外一种更简单的方法是在配置文件中配置命令,直接生成整个项目的测试报告:
1)首先,在该项目路径下创建要测试的类包,测试报告包,配置文件pytest.ini
2)在配置文件中配置要运行的命令

[pytest]
#addopts可添加多个命令行参数
addopts=-s --html=./report/pytestreport.html #生成报告的命令
#以下是搜索定位到要执行的文件
testpaths=./scripts 
python_files=test_*.py 
python_classes=Test_*

3)直接在终端输入pytest回车,即可执行所有符合条件的用例,并且生成对应的测试报告,测试报告在report文件夹下。

注意:若报告要显示xml的格式,可以改为:- -html=./report/pytestreport.xml

4.2 控制函数执行顺序插件

默认情况下,pytest是根据测试方法名由小到大执行的,可以通过第三方插件包改变其运行顺序。
作用:以函数修饰符的方式标记被测函数,通过参数控制函数执行顺序

安装:pip install pytest-ordering

使用方法:
1.标记于被测函数,@pytest.mark.run(order=x) x表示执行的顺序
2.根据order传入的参数来决定运行顺序:

  • order值全为正数或全为负数时,值越小,优先级越高
  • 正数和负数同时存在,正数优先级高
    总结:0>较小整数>较大的整数>无标记>较小的负数>较大的负数

例:

import pytest

class Test_report:
    @pytest.mark.run(order=3)
    def test_12(self):
        print('121212')

    @pytest.mark.run(order=1)
    def test_34(self):
            print('343434')

    @pytest.mark.run(order=2)
    def test_45(self):
        print('454545')

pytest,python,pytest,单元测试

4.3 失败重试插件

pytest-rerunfailures 作用:使用命令方式控制失败函数的重试次数
安装:pip install pytest-rerunfailures

使用方法:
命令行格式: --reruns n
n 表示重试的次数

命令行运行:pytest -s test_report.py --reruns 2
对出错的用例再重新执行两次

配置文件写法:

[pytest]

addopts=-s --html=./scripts/report/pytestreport.html  --reruns 2
testpaths=./scripts 
python_files=test_*.py 
python_classes=Test_*

pytest,python,pytest,单元测试

4.4 多条断言失败也都运行

场景:一个方法中多条断言,想要报错的都执行一下
安装pip install pytest-assume
调用:pytest.assume(1==4)
pytest,python,pytest,单元测试

5、fixture装置(夹具)

fixture是pytest特有的功能,用pytest.fixture来标志,以装饰器形式定义在函数上,在编写测试用例的时候,可以将此函数名称作为传入参数,pytest将会以依赖注入方式,将该函数的返回值作为测试函数的传入参数。

fixture是基于模块来执行的,每个调用fixture的函数都可以触发一个fixture函数,自身也可以调用其他的fixture。

可以将fixture看作是资源,在执行测试用例之前需要配置这些资源,执行完后需要去释放资源。比如module类型的fixture适合于那些许多测试用例都只需要执行一次的操作。

fixture还提供参数化功能,根据配置和不同组件来选择不同的参数。

5.1 fixture函数作用

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

5.2 使用说明

pytest.fixture(scope=‘function’,params=None,autouse=False,ids=None,name=None)
也可以不传参数!!所有值都以默认值存在。

常用参数说明:
scope:标记方法的作用域
 1. “function":默认值,表示每个测试方法都要执行一次
 2. ”class":作用于整个类,表示每个类的所有测试方法只运行一次
 3. “module:作用域整个模块,每个module的所有测试方法只运行一次
 4. ”session":作用于整个session, 每个session只运行一次(慎用!!!)
 
 params:list类型,默认None,接收参数值,对于param里面的每个值,fixture都会区遍历执行一次
 autouse:是否自动运行,默认为false,为true时,此session中的所有测试函数都会调用fixture
以参数形式传递

定义一个fixture装饰的方法,然后通过参数形式传递给其他函数来实现调用该函数。

import pytest

@pytest.fixture()
def test_1():
    print('hhhhhhhhhhhhhhhhhhhhhhhh')

def test_2(test_1):
    print('222222')

def test_3(test_1):
    print('333333')

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

pytest,python,pytest,单元测试

作为函数应用

以装饰器的形式传递参数:@pytest.mark.usefixtures(‘test_1’)
不论给函数还是给类设置fixture装置,都可以通过@pytest.mark.usefixtures(‘test_1’)来装饰。

import pytest

@pytest.fixture()
def test_1():
    print('hhhhhhhhhhhhhhhhhhhhhhhh')

@pytest.mark.usefixtures('test_1')
def test_2():
    print('222222')

@pytest.mark.usefixtures('test_1')
class Test_adb():
    def test_3(test_1):
        print('333333')

    def test_4(test_1):
        print('4444444444')

pytest,python,pytest,单元测试

带参数使用–设置默认启动形式

autouse:设置自动运行,为true时,此session中的所有测试函数都会调用fixture,不需要特意标识。

import pytest

@pytest.fixture(autouse=True)
def test_1():
    print('hhhhhhhhhhhhhhhhhhhhhhhh')
    
def test_2():
    print('222222')

class Test_adb():
    def test_3(test_1):
        print('333333')

    def test_4(test_1):
        print('4444444444')

pytest,python,pytest,单元测试

设置作用域class

设置作用域scope="class“ 则整个类中装饰函数只在最开始执行一次。当然了,在类以外的地方还是都默认执行的。

import pytest

@pytest.fixture(scope="class",autouse=True)
def test_1():
    print('\nhhhhhhhhhhhhhhhhhhhhhhhh')

def test_2():
    print('222222')
def test_666():
    print('6666666666666666666666')

class Test_adb():
    def test_3(test_1):
        print('333333')

    def test_4(test_1):
        print('4444444444')
设置作用域为module

在整个模块中最开始的时候执行一次,并且只执行一次。尽管其他地方通过直接调用装饰函数,也不会再执行。

import pytest

@pytest.fixture(scope="module",autouse=True)
def test_1():
    print('\nhhhhhhhhhhhhhhhhhhhhhhhh')

def test_2():
    print('222222')
def test_666():
    print('6666666666666666666666')

class Test_adb():
    def test_3(test_1):
        print('333333')

    def test_4(test_1):
        print('4444444444')

设置参数化
from urllib import request
import pytest

@pytest.fixture(params=[1,2,3])
def data(request):
    return request.param

class Test_adb():
    def test_3(self,data):
        print(f'有几个?{data}个人')

    def test_4(test_1):
        print('4444444444')

if __name__=='__main__':
    pytest.main("test_12.py")

pytest,python,pytest,单元测试

6、跳过测试函数

使用skipif函数设置,可以根据特定条件,不执行标识的测试函数。
@pytest.mark.skipif(condition=True,reason=“xxx”)

参数说明:
condition:跳过的条件,必传参数
reason:标注跳过的原因,必传参数,而且必须是string类型

import pytest

class Test_adb():
    def test_3(self):
        print('\n333333333')

    @pytest.mark.skipif(condition=True,reason="跳过")
    def test_4(self):
        print('\n4444444444')

    def test_5(self):
        print('\n5555555555')

if __name__=='__main__':
    pytest.main("test_12.py")

pytest,python,pytest,单元测试

7、标记为预期失败函数

适用场景:标记某测试函数为失败,实际上函数执行了,只是类似手动给它设置为失败状态。
方法:
@pytest.mark.xfail(condition=2>1,reason=“不执行test_4函数”,raises=None,run=True,strict=False)

常用参数:
condition:预期失败的条件,必传参数
reason:失败的原因,必传参数

import pytest

class Test_adb():
    def test_3(self):
        print('\n333333333')

    @pytest.mark.xfail(condition=2>1,reason="不执行test_4函数",raises=None,run=True,strict=False)
    def test_4(self):
        print('\n4444444444')

    def test_5(self):
        print('\n5555555555')

if __name__=='__main__':
    pytest.main("test_12.py")

pytest,python,pytest,单元测试

8、函数数据参数化

作用:方便测试函数对测试属性的获取
方法:
@pytest.mark.parametrize(argnames=“data_test”,argvalues=[(1,2,3),(4,5)],indirect=False,ids=None,scope=None)

常用参数:
argnames:参数名
argvalues:

  1. 参数对应值,类型必须为List
    2.当参数为一个时,参数的格式为:[value]
    3.当参数个数大于一个时,格式为:[(param_value,param_value2),(param-value,param_value2)…]

注意:当参数值为n个,测试方法就会运行N次,类似将函数嵌入for循环执行一样

import pytest

class Test_adb():
    def test_3(self):
        print('\n333333333')

    @pytest.mark.parametrize(argnames="data_test",argvalues=[(1,2,3),(4,5)])
    def test_4(self,data_test):
        print(data_test)
        print('\n4444444444')

    def test_5(self):
        print('\n5555555555')

if __name__=='__main__':
    pytest.main("test_12.py")

pytest,python,pytest,单元测试

还可以叠加多个mark的方法:

	@pytest.mark.parametrize(argnames="data_test",argvalues=[(1,2,3),(4,5)])
    @pytest.mark.xfail(condition=2>1,reason='hahahah,搞错啦')
    def test_4(self,data_test):
        print(data_test)
        print('4444444444')

三、PO模式简介

PO模型是Page Object Mode的简写,页面对象。
作用:把测试页面和测试脚本进行分离,即把页面封装成类,供测试脚本进行调用。

优点:

  • 提高代码可读性
  • 减少代码的重复
  • 提高代码的可维护性,特别是针对UI界面频繁变动的项目

缺点:

  • 造成项目结构比较复杂,因为是根据流程进行了模块化处理

代码抽取

手机发送短信的例子:

目录:
pytest,python,pytest,单元测试

代码:一般先抽取业务功能代码,再次再抽取业务功能中用到的信息。

抽取功能代码:
创建page目录(名字是默认的,不能更改),在该目录中创建py文件,把新增短信,输入内容等功能进行抽取

base命令包含的内容:
constants.py

appPackages="com.android.settings"
appActivity=".Settings"

base_driver.py

from . import constants
from selenium import webdriver

def base_driver(appPackages,appActivity):
    devices_info = {}
    devices_info['platformName'] = 'Android'
    devices_info['platformVersion'] = '5.1.1'
    devices_info['deviceName'] = '127.0.0.1:21503'
    # 发送中文时,自动转换
    devices_info['unicodeKeyboard'] = True
    devices_info['resetKeyboard'] = True

    devices_info['appPackage'] = constants.appPackages
    devices_info['appActivity'] = constants.appActivity

    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', devices_info)
    driver.implicitly_wait(30)
    return driver

page包含的内容:
send_msg.py


class send_msg():
    def __init__(self,driver):
        self.driver=driver

    def add(self):
        # 先一步一步打开短信编辑发送界面
        self.driver.find_element_by_xpath("//*[contains(@text,'短信')]").click()
        self.driver.find_element_by_xpath("//*[contains(@text,'新增')]").click()

    def receiver(self):
        # 然后定位到收件人、收件内容
        receive_data = self.driver.find_element_by_xpath("//*[contains(@text,'接收者')]")
        receive_data.clear()
        receive_data.send_keys('13357578462')

    def send_msgmtd(self,driver):
        send_list = ['1212', 'hhhhahaa', '哈哈哈啊哈哈😄']
        send_msg = driver.find_element_by_xpath("//*[contains(@text,'发送内容')]")
        send_btn = driver.find_element_by_xpath("//*[contains(@text,'发送')]")
        # 遍历写入数据并发送
        for data in send_list:
            send_msg.clear()
            send_msg.send_keys(data)
            send_btn.click()

script包含的内容:
test_sendmsg.py

from selenium import webdriver
from page.send_msg import *
from base  import *
class test_sendmsg():
    def setup_class(self):
        self.driver = base_driver()
        self.sendmsg=send_msg(self.driver)

    def teardown_class(self):
        self.driver.close_app()
        self.driver.close()

    def test_send_msg(self):
        self.sendmsg.add()
        self.sendmsg.receiver()
        self.sendmsg.send_msgmtd()


分布式

pytest,python,pytest,单元测试

pytest,python,pytest,单元测试

四、allure报告

allure报告,点击传送门

调试

控制台输入:pytest -k test_测试类.py --log-level=debug
通过调整log等级查看日志情况

FAQ

  1. 报错:不合法得字符转换:‘gbk’ codec can’t decode byte 0xaf in position 76: illegal multibyte sequence

原因:pytest.ini文件有问题,可能是有中文或者其他内容出问题。文章来源地址https://www.toymoban.com/news/detail-742890.html

到了这里,关于python之pytest的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Pytest自动化测试框架---(单元测试框架)

    unittest是python自带的单元测试框架,它封装好了一些校验返回的结果方法和一些用例执行前的初始化操作,使得单元测试易于开展,因为它的易用性,很多同学也拿它来做功能测试和接口测试,只需简单开发一些功能(报告,初始化webdriver,或者http请求方法)便可实现。 但自

    2024年02月14日
    浏览(70)
  • Pytest单元测试框架 —— Pytest+Allure+Jenkins的应用

    一、简介 pytest+allure+jenkins进行接口测试、生成测试报告、结合jenkins进行集成。 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高 allure-pytest是python的一个第三方库。用于连接pytest和allure,使它们可以配合在一起

    2024年02月07日
    浏览(59)
  • 软测入门(六)pytest单元测试

    pytest是python的一种单元测试框架,同自带的unit test测试框架类似,但pytest更简洁高效。 单元测试: 测试 函数、类、方法能不能正常运行 测试的结果是否符合我们的预期结果 通过pytest包使用 默认情况下:在main中直接使用 pytest 的main()方法,会把文件中所有 test_* 开头的方法

    2024年02月07日
    浏览(73)
  • Pytest单元测试系列[v1.0.0][pytest插件常用技巧]

    pytest-xdist:Run Tests in Parallel [https://pypi.python.org/pypi/pytest-xdist] 在自动化测试中有些资源只能同时被一个测试用例访问,如果不需要同时使用同一个资源,那么测试用例便可以并行执行 执行命令pip install pytest-xdist安装插件 使用pytest-xdist执行测试 参数说明 -n auto 自动侦测系统里

    2024年02月03日
    浏览(36)
  • 精进单元测试技能——Pytest断言的艺术

    本篇文章主要是阐述Pytest在断言方面的应用。让大家能够了解和掌握Pytest针对断言设计了多种功能以适应在不同测试场景上使用。 了解断言的基础 在Pytest中,断言是通过  assert  语句来实现的。简单的断言通常用于验证预期值和实际值是否相等,例如: 然而除此之外,Pyt

    2024年01月20日
    浏览(81)
  • 精进单元测试技能 —— Pytest断言的艺术!

    本篇文章主要是阐述Pytest在断言方面的应用。让大家能够了解和掌握Pytest针对断言设计了多种功能以适应在不同测试场景上使用。 了解断言的基础 在Pytest中,断言是通过  assert  语句来实现的。简单的断言通常用于验证预期值和实际值是否相等,例如: 然而除此之外,Pyt

    2024年02月03日
    浏览(36)
  • Pytest:单元测试的宠儿,让 Bug 无处藏身!

    在软件开发中,确保代码的质量和稳定性是至关重要的。单元测试作为保障代码质量的重要手段之一,为开发者提供了在开发过程中验证代码逻辑的有效方式。而在众多的单元测试框架中,Pytest 凭借其简洁灵活的语法和强大的功能逐渐成为了开发者们的宠儿。本文将深入探讨

    2024年01月17日
    浏览(42)
  • Python+Pytest压力测试

    在现代Web应用程序中,性能是至关重要的。为了确保应用程序能够在高负载下正常运行,我们需要进行性能测试。 今天,应小伙伴的提问, 老向老师来写一个Pytest进行压力测试的简单案例。 这个案例的测试网站我们就隐藏了,不过网站的基本情况是: 阿里框架:FastAdmin.n

    2024年02月12日
    浏览(92)
  • Python测试之Pytest详解

    当涉及到 python 的测试框架时, pytest 是一个功能强大且广泛应用的第三方库。它提供简洁而灵活的方式来编写和执行测试用例,并具有广泛的应用场景。下面是 pytest 的介绍和详细使用说明: pytest 是一个用于 python 单元测试的框架,它建立在标准的 unittest 模块之上,并提供

    2024年02月05日
    浏览(33)
  • Python测试框架 Pytest —— mock使用(pytest-mock)

    安装:pip install pytest-mock 这里的mock和unittest的mock基本上都是一样的,唯一的区别在于pytest.mock需要导入mock对象的详细路径。 先将需要模拟的天气接口,以及需要模拟的场景的代码写好,然后在进行遵循pytest的用例规范进行书写关于mock的测试用例 通过上述代码,提供pytest中

    2024年02月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包