当前位置: 首页>编程语言>正文

基于pytest的接口自动化 pytest做ui自动化

一、简介

pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高

二、 pytest单元测试框架

a. 特点

1. pytest是python当中的一个单元框架,比unittest更灵活

2. pytest和selenium,requests,appium结合实现web自动化,接口自动化,app自动化

3. pytest可以实现测试用例的跳过以及reruns失败用例重试

4. pytest可以和allure生成非常美观的测试报告

5. pytest可以和Jenkins持续集成

b. pytest插件

1. pytest

2. pytest-html 生成html格式的自动化测试报告

3. pytest-xdist 测试用例分布式执行,多CPU分发

4. pytest-ordering 用于改变测试用例的执行顺序

5. pytest-rerunfailures 用例失败后的重跑

6. allure-pytest 用于生成allure的报告

c. pytest插件安装

1. 全局安装, 这里以windows为例,首先需要安装好python环境, 然后设置pip为全局环境变量,新建一个requirements.txt,将所有插件按顺序复制到txt文档中,然后打开cmd运行 pip install -r 绝对路径\requirements.txt来安装插件即可

2. 虚拟环境安装(具体可以网上搜一下如何创建虚拟环境),然后使用相同的命令安装,这时候这些插件就只能作用于当前工作目录

d. pytest使用规则

1. 模块名必须以test_开头或者_test结尾

2. 测试类必须以Test开头,并且不能有init方法

3. 测试方法必须以test开头

e. pytest测试用例运行模式

主函数模式

1. 运行所有 pytest.main()

2. 指定模块 pytest.main(['-vs',  'module'])           # 模块为可选,如果没有默认运行当前项目下的所有用例

3. 指定目录 pytest.main(['-vs', './path'])               # 运行的主脚本需要在整个项目根目录下,然后指定目录

4. 通过nodeid指定用例运行: nodeid由模块名,分隔符,类名,方法名,函数名组成

例: pytest -vs ./目录/xx.py::类名::方法名             # 4方法不常用

示例:

pytest.main()                                 # 运行所有
pytest.main(['-vs', 'test_module'])           # 运行指定模块
pytest.main(['./test_path'])                  # 运行指定目录

命令行模式

1. 运行所有 pytest

2. 指定模块 pytest -vs xx.py #模块为可选,如果没有默认运行当前项目下

3. 指定目录 pytest -vs ./目录 #运行的主脚本需要在整个项目根目录下,然后指定目录

示例:

pytest                            # 运行所有
pytest xx.py                      # 运行指定模块
pytest './test_path'              # 运行指定目录

通过读取pytest.ini配置文件运行

pytest.ini 是pytest单元测试框架的核心配置文件

1. 位置:  一般存放在项目的根目录

2. 编码:必须是ANSI, 可以用Notepad++修改编码格式

3. 作用:改变pytest默认的行为, 例如文件名可以不以Test_开头,类名,函数名皆可

4. 运行的规则:不管是主函数模式运行,还是命令行运行模式,都会去读取这个配置文件。

5. pytest.ini格式:

        [pytest]

# 命令行参数, 用空格分隔,可选

# 测试用例文件夹,可自己配置,可选

# 配置测试搜索的模块文件名称,可选

# 配置测试搜索的测试类名,可选

# 配置测试搜索的测试函数名,可选

        注: 配置文件中不要保留中文,这里只是注释,编码ANSI会乱码

参数解释

-s: 表示输出调试信息,包括print打印的消息
-v: 显示更详细的信息
-vs: 两个参数可以一起使用
-n process_num: 支持多线程或者分布式运行用例          # 需要插件pytest-xdist
--reruns num:用例失败后重新执行                                # 需要插件pytest-rerunfailures
-x: 表示只要一个用例报错则测试停止
--maxfail=2: 出现两个用例失败就停止
-k: 根据测试用例的部分字符串指定测试用例
--html xxx.html:生成html的测试报告

f. pytest执行顺序

1. pytest 默认执行顺序是自上而下

2. 通过装饰器 @pytest.mark.run(order=1)来指定顺序,当有多个装饰器指定顺序一样时,按照自上而下执行,此装饰器需要安装插件pytest-ordering

g. 分组执行 markers

markers是pytest里面用于区分测试用例的标签,主要有两种使用方法

1. 命令行模式 pytest -vs -m "标签名"

2. pytest.ini文件中增加 markers[标签名: 标签说明]

[pytest]
......                # 前面内容省略
markers:

label1:标签说明
label2:标签说明

示例:

import pytest

class TestCase:
    @pytest.mark.label1
        xxxx

    @pytest.mark.label2
    def test_02(self):
        xxxx

命令行执行: pytest -vs -m ”label“ or pytest -vs -m "label1 or label2"
如果使用pytest.ini 则直接pytest -vs即可

h. 跳过测试用例

有条件跳过

@pytest.mark.skipif(condition, reason)

示例:

age =18
@pytest.mark.skipif(age >=18, reason ='已成年')
def xxx(self):
    xxx

#条件达成True,跳过测试用例,反之false,执行用例

无条件跳过

@pytest.mark.skipif(reason)

@pytest.mark.skipif('理由')
@pytest.mark.skipif(reason ='理由')

# 两种方式皆可

i. pytest测试夹具(前置后置)

setup/teardown

import pytest

class Test:
    def setup(self):
        print('测试用例执行前执行:打开浏览器')
    
    def test_01(self):
        print('测试用例一')

    def teardown(self):
        print('测试用例执行后执行: 关闭浏览器')

setup_class/teardown_class

import pytest

class Test:
    def setup_class(self):
        print('在每个类执行前的初始化操作: 比如创建日志对象,创建数据库链接')
    
    def test_01(self):
        print('测试用例一')

    def teardown_class(self):
        print('在每个类执行后的扫尾操作: 比如销毁日志对象,关闭数据库链接')

@pytest.fixture 装饰器

@pytest.fixture(scope=",  params=", ids='', names='', autouse=False)

scope

scope表示的是被@pytest.fixture标记的方法的作用域

1. function

示例

@pytest.fixture(scope='function')                                                 # 类似于setup/teardown

import pytest

@pytest.fixture(scope='function')		               
def my_fixture():
    print('这是前后置方法,可以实现部分以及全部用例的前后置')
    yield
    print('后置测试方法, 用例执行完之后执行')

class Test:
    def test_01(self, my_fixture):
        print('测试一')

示例

@pytest.fixture(scope='function',autouse=True)

下面用例就无需添加my_fixture,每个用例执行前后都会执行my_fixture函数, autouse= False则不执行

import pytest

@pytest.fixture(scope='function', autouse=True)		                #类似于setup/teardown
def my_fixture():
    print('这是前后置方法,可以实现部分以及全部用例的前后置')
    yield
    print('后置测试方法, 用例执行完之后执行')

class Test:
    def test_01(self):
        print('测试一')

结果: 在用例执行前后执行my_fixture函数

2. class

示例

@pytest.fixture(scope='class',autouse=True)        # 类似于setup_class/teardown_class

scope为class的时候,必须配autouse=True,因为autouse默认是False,不附上则不执行

import pytest

@pytest.fixture(scope='class', autouse=True)		              
def my_fixture():
    print('这是前后置方法,可以实现部分以及全部用例的前后置')
    yield			#带yield的函数是一个生成器,附上要return生成内容即可
    print('后置测试方法, 用例执行完之后执行')

class Test:
    def test_01(self):
        print('测试一')

class Test1:
    def test_02(self):
        print('测试二')

结果: 在Test类的前后执行my_fixture函数,如果有多个类,就每个类的前后执行前置后置一次

3. Module

示例

@pytest.fixture(scope='module',autouse=True)

scope为module的时候,必须配autouse=True,因为autouse默认是False,不附上则不执行

import pytest

@pytest.fixture(scope='module', autouse=True)		              
def my_fixture():
    print('这是前后置方法,可以实现部分以及全部用例的前后置')
    yield			#带yield的函数是一个生成器,附上要return生成内容即可
    print('后置测试方法, 用例执行完之后执行')

class Test:
    def test_01(self):
        print('测试一')

class Test1:
    def test_02(self):
        print('测试二')

结果: 在Test类的前和Test1类后执行my_fixture函数

4. package/session

这两种用的比较少,以后用到再更新

params

参数化, 支持 [1. list[],2. tuple(),3. list_dict[{},{},{}],4. tuple_dict({},{},{}) ]

示例

import pytest

@pytest.fixture(scope='function', params=['年','月','日'])	#params是参数名
def my_fixture(request):				        #request为固定写法
    return request.param			            #param是属性名

class Test:
    def test_01(self, my_fixture):
        print('测试一')
        Print('----------' + str(my_fixture))	#这里需要强制转换成str

结果: 在方法test01每次执行后,打印年,月,日的信息

注: 如果不参数化的时候可以直接return一个字符串, 当该函数继续支持前后置的时候可以使用以下代码

import pytest

def my_fixture(request):				
    print('前置')
    yield request.param		#return和yield都表示返回的意思,但是return后面不能有代码,但yield可以
    print('后置')

ids

使用params参数化时,给每一个值设置一个变量来替换结果中输出的unicode

@pytest.fixture(scope='function', params=['年', '月' ,'日'], ids=['nian' ,'yue' ,'ri'])

name

给表示被@pytest.fixture标记的方法取一个别名

注: 当设置别名后原本的名称就不能再当参数使用了

import pytest

@pytest.fixture(scope='function', name='aaa')

class Test:
    def test_01(self, aaa):
        print('测试一')

autouse

是否自动执行,默认为False,True则自动执行

不常用的另一种方法

conftest.py和@pytest.fixture结合使用全局的前置应用

conftest.py文件是单独存放的一个夹具配置文件,名称不能修改

可以在不同的py文件中使用同一个fixture函数

原则上 conftest.py和需要调用的用例在同一层目录,无须import操作

可以每个模块全局,也可以整个项目全局,注意这种使用情况的话,调用顺序为先项目全局再模块全局

总结

1. setup/teardown, setup_class/teardown_class 作用于所有用例或者类

2. @pytest.fixture() 作用可是是部分也可以全局前后置

3. conftest.py和@pytest.fixture结合使用, 作用域全局的前后置

j. 断言

assert condition

k. pytest+allure测试报告

1. 环境搭建-Windows

手工下载: https://github.com/allure-framework/allure2/releases/,下载完成后设置添加系统全局变量指向到allure插件的bin目录,例如 path: C:\allure-xx\bin

验证添加是否成功,打开cmd,运行allure --version,查看是否添加成功

2. 生成json格式临时报告

命令行模式 pytest -vs --alluredir ./temp

pytest.ini文件
[pytest]
addopts = -vs --alluredir ./temp
.....

3. 生成allure的报告

allure generate ./temp -o ./report --clean

参数解释
./temp 临时json格式的报告路径
-o 输出output参数
./report 生成allure报告的路径
--clean 清空./report路径原来的报告

l.  @pytest.mark.parametrize装饰器

@pytest.mark.parametrize(args_name, args_value),一般有两种用法

args_name: 参数名

args_value: 参数值(list, tuple,list_dict, tuple_dict), 有多个值用例就会执行多次

1. 第一种用法

传入一个list,然后查看结果,将整个列表 ”年 月 日“打印出来

import pytest

class TestApi:
    @pytest.mark.parametrize('args',['年', '月', '日'])        # 传入了一个list
    def test_01(self, args):
        print(args)


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

2. 第二种用法

和unittest里面ddt的@unpack解包一致,将两个列表item1,item2依次传入test01用例,结果打印两次分别是”年 月 日“,”小时 分 秒“

import pytest

class TestApi:
    @pytest.mark.parametrize('args, item1, item2', [['年', '月', '日'],['小时', '分', '秒']])
    def test_01(self, args, item1, item2):
        print(args, item1, item2)


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

m. yaml文件--实现接口自动化

yaml是一种数据格式,支持注释,换行, 多行字符串,裸字符串(整形,字符串),需要安装选择PyYAML插件

1. 用于全局的配置文件 ini/yaml

2. 用于写测试用例(接口测试用例)

语法规则

区分大小写

使用缩进表示层级,不能使用tab键缩进,只能用空格(和python一样)

缩进没有数量限制,只要前面是对齐的就行

注释也是#

数据组成

Map对象:

格式:字典键值对

一行写法:
test:{name: '名称', age: '年龄'}

多行写法:
test:
  name: '名称'
  age: '年龄'

数组:

格式:列表字典键值对

一行的写法
-
test: [{name: ’名称‘},{age: ’年龄‘}]

多行写法:
-
  test
  - name: ‘名称’
  - age: ’年龄‘
-
  test1:
  - name: ’名称‘
  -

接口自动化实例:

yaml文件就以字典键值对为例

test:{name: '名称', age: '年龄'},确保文件和脚本在同一目录,这里python运行即可,不要用pytest

import yaml


class YamlUtil:
    def __init__(self, yaml_file):
        """
        通过init方法将yaml文件传入这个类
        :param yaml_file:
        """
        self.yaml_file = yaml_file

    def read_yaml(self):
        """
        读取yaml, 对yaml反序列化, 就是把yaml格式转换成dict格式
        :return:
        """
        with open(self.yaml_file, encoding='utf-8') as file_object:
            value = yaml.load(file_object, Loader=yaml.FullLoader)
            print(value)

if __name__ == '__main__':
    YamlUtil('test_api.yaml').read_yaml()

结果: {'test': {'name': '姓名', 'age': '年龄'}


https://www.xamrdz.com/lan/5jx1951298.html

相关文章: