加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

接口自动化测试框架 pytest+ymal+allure+requests+redis


联系方式

QQ 529548204
邮箱 529548204@qq.com
如果有问题请联系我 大家共同学习共同进步~

更新日志

2022年6月7日 更新 取消config中http类型 改为yaml数据内
2022年5月30日 更新 YAML读取时间格式datetime数据后 json处理方式
2022年5月20日 更新增加jenkins持续集成说明配置方法等
2022年5月17日 更新增加xml参数处理,增加自定义加密方式(加密规则需要自己写 需要一定编码能力)

前言

环境要求

python 3.9
redis (存放用例数据)
mysql (测试环境数据库)
jdk
allure
持续集成:
    docker
    jenkins

框架采用python的pytest模块, 搭配requests以及allure测试报告,可以发送钉钉通知邮件通知, 支持自定义接口加密,util.tools.encryption文件内自己编辑加密规则, 可以根据yaml测试数据自动生成用例, 支持接口关联, 支持类似jmeter的函数助手, 可以通过脚本进行接口录制,辅助编写yaml测试数据文件, 支持数据库断言, 支持分布式,jenkins持续集成。

注意

单用例调试时需要执行一次util\tools\readYamlFile.py将测试数据存入redis

一、目录结构

|--接口自动化测试框架 # 主目录
   ├─ common # 封装断言以及requests的方法
   ├─ caches # 本地缓存保存路径
   ├─ config # 配置文件读取
     └─ config.ini
   ├─ testsuite # 测试相关文件
     ├─ datas #测试数据
       └─ 项目文件夹 名称同config中 testname一致 # 可以通过newproject脚本生成
          └─ login.yml # 用例数据 格式参考下面YAML PARAM格式说明
     ├─ testcase
       └─ 项目文件夹 名称同config中 testname一致 # 测试用例 可以通过writepage脚本生成
         └─ test_login.py
     └─recording # 录制脚本文件夹放录制的接口文档
   ├─ util # 常用工具 用例生成 接口录制
     ├─ tools # 内部调用工具方法包含yaml读取 函数助手 数据库链接等
     └─ scripts # 包含生成新项目,自动生成用例,接口录制
   ├─ log # 日志
   ├─ report # allure测试报告	
   ├─ pytest.ini	   # pytest配置
   ├─ requirements.txt		 
   ├─ README.md          
   └─ setupMain.py	# 整体执行程序。

二、关键文件介绍

1.yaml测试数据格式

1.1 本地缓存介绍

保存本地缓存方法为3种
    1. body  请求体内的参数中保存:
       body如果是 "id=2&path=haha" 会转换成字典 然后根据path使用jsonpath取值
    2. response : 从json格式的响应结果中获取
    3. cookies: 保存响应结果的cooies到本地
读取本地缓存方法

将需要替换为缓存数据的内容改成:$caches(cookies)$

示例:


    cache: # 本地缓存
      - cachefrom: 'body' 
        path: '$.code' 
        name: 'code'
        # 使用方法 需要的地方替换为$caches(code)$
      - cachefrom: 'response' 
        path: '$.data'
        name: 'data'
        # 使用方法 需要的地方替换为$caches(data)$
      - cachefrom: 'cookies' 
        path:  # cookies 时path为空
        name: 'cookies'
        # 使用方法 需要的地方替换为$caches(cookies)$ 

1.2 接口关联介绍

通过relevance字段来判断是否需要关联 如果不需要relevance字段为空即可

示例:

下面示例为 关联接口为tradeAdd 与 tradeAdd2两条yaml数据中case的第一条和第二条 分别去这两个接口返回结果的 id 并命名为tradeId 、tradeId2 内存中会保存成字典格式 {"tradeId":"10","tradeId2":"11"}
读取方法:$relevance(tradeId2)$

img.png

    relevance:
      response: 
          - relCaseName: shangchuan # 其他testcase的ID
            relCaseNum: 1 # 关联的case数组里 第几条数据
            reldata:
              - value: $.data.fileName # 当前返回结果的jsonpath
                name: fileName # 关联值名称
              - value: $.data.policy # 当前返回结果的jsonpath
                name: policy # 关联值名称
              - value: $.data.signature # 当前返回结果的jsonpath
                name: signature # 关联值名称
          - relCaseName: tradeAdd2 # 其他testcase的ID
            relCaseNum: 2 # 关联的case数组里 第几条数据
            reldata:
              - value: $.data.fileName # 当前返回结果的jsonpath
                name: fileName # 关联值名称
              - value: $.data.policy # 当前返回结果的jsonpath
                name: policy # 关联值名称
              - value: $.data.signature # 当前返回结果的jsonpath
                name: signature # 关联值名称

1.3 参数介绍

file : 通过case外关键字file判断是否需要上传文件 如果需要则格式为:{上传文件的参数名:文件路径}

param:包含两种请求格式
(1)json格式 :
{ "username": "finsiot","password": "$caches(pwd)$" # 读取缓存值 }(同样适用于xml格式 会根据请求头application/xml或者text/xml 将字典转换成xml类型)
(2)param格式
username=admin&password=123

urlparam为路径参数:{ id: 123 }

会根据字典转换成 路径参数 addressv1/api/$url(id)$/中会根据id替换为123

    data:
      file: {
        files: D:\test\test.csv # 上传文件的参数名:文件路径
      }
      param: {
        "username": "finsiot","password": "$caches(pwd)$" # 读取缓存值
      }
      urlparam: {
      id: 123
      }# 路径参数 v1/api/$url(id)$/

1.4 断言介绍

jsonpath json格式数据断言: 根据json路径格式来获取实际结果同value中的预期结果进行判断 sqlassert 数据库结果断言 可同时判断多个结果值 根据sql中的查询语句查询出来的 第一条结果进行判断 time响应时间断言 默认为2秒 code http响应码断言

    assert:
      jsonpath:
        - {
          "path": "$.data.expense_trend[0].peak_hour.peak_hour",
          "value": "123",  # 预期结果
          "asserttype": "==" # 判断相等
        }
        - {
          "path": "$.code",
          "value": 0,
          "asserttype": "=="
        }
        - {
          "path": "$.data.id",
          "value": 196,
          "asserttype": "=="
        }
      sqlassert:
      # 如果不需要 此字段置空即可
        - {
          "datas": [
            {
              "path": "$.data.id",
              "name": "id"
            },
            {
              "path": "$.data.username",
              "name": "username"
            },
          ],
          "sql": "select * from saas.user where username = '****'", 
           # 取数据库查询出的第一条数据进行验证 如果存在 列名 username 值为$.data.username则通过
          "db_name": "database" # 判断链接那个数据库
          }
      time: 2 # 响应时间断言
      code: 200

1.5 生成随机数据介绍

部分数据采用faker库生成

    int_num = "$RandomPosInt(1,333)$" # 267
    str_num = '$RandomString($RandomPosInt(2,23)$)$$RandomPosInt(1,333)$' # AbE3c14580f29aDFe5
    float_num = '$RandomFloat($RandomPosInt(2,13)$,$RandomPosInt(2,13)$,$RandomPosInt(2,13)$)$' # 11.84864
    time_num = '$GetTime(time_type=else,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,0,0)$' # 当前时间 2022-04-14 13:27:01
    time_num2 = '$GetTime(time_type=future,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,3,0)$' # 未来时间3天后 2022-04-17 13:32:42
    time_num3 = '$GetTime(time_type=past,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,3,0)$' # 过去时间3天前 2022-04-11 13:33:24
    choice_num = '$Choice($RandomPosInt(2,13)$)$'  # 6
    email = "$faker(email)$"# 邮箱 # xkong@example.net
    idcard = "$faker(idcard)$" # 130802196003197594
    province = "$faker(province)$" # 新疆维吾尔自治区
    city = "$faker(city)$" # 鹏市
    phone_number = "$faker(phone_number)$" # 15070673645
    name = "$faker(name)$" # 许云

1.6 后置请求处理

使用场景: 新增数据A之后一系列用例执行完需要后置来还原数据形成业务闭环. datatype 有3种类型 param json 和urlparam
dataname为后置关联的参数中参数名称
path为当前请求返回结果的jsonpath 根据path的值更换后置处理参数值
如果不需要后置处理 teardown 置空即可

      teardown:
        - tdName: pointDel # 其他testcase的ID
          tdNum: 1 # 关联的case数组里 第几条数据
          tddata:
            - datatype: param
              dataname: name
              path: $.name
            - datatype: urlparam
              dataname: pointId
              path: $.id
        - tdName: pointAdd # 其他testcase的ID
          tdNum: 1 # 关联的case数组里 第几条数据
          tddata:
            - datatype: json
              dataname: name
              path: $.name
            - datatype: urlparam
              dataname: pointId
              path: $.id

三、文件展示

3.1yaml文件展示

!!!所有case的id 务必唯一!!!

name: "登录" # 测试用例模块名称 token: Authorization# 判断此接口是否使用token false 或者"cookie"或者"Authorization"等 如果不需要 置空或者填写false order: 1 用例执行顺序 @pytest.mark.run(order=1) # 因为此功能不支持分布式录制中已取消 file: bool值判断 true为此接口需要上传文件参数 case: 测试用例数据


login: # caseID **请务必唯一**
  name: "登录" #测试用例模块
  token: false # 判断此接口是否使用token false 或者"cookie"或者"Authorization"等
  # token: "Authorization"
  order: 1 # 用例执行顺序 @pytest.mark.run(order=1) 因为此功能不支持分布式录制中已取消
  file: true # bool值 true为需要文件的接口
  case:
  - info: "用户名登录-成功" # 用例信息
    http: https # http
    host: 'host' # config.ini里面 请求host的key
    address: '/v1/apps/$url(region_id)$/' # $url(region_id)$ 正则匹配参数中的路径参数
    method: 'post'
   
    cache: # 本地缓存
        # 保存本地缓存方法为3种
        # 1. body  请求体内的参数中保存:
        #    body如果是 "id=2&path=haha" 会转换成字典 然后根据path使用jsonpath取值
        # 2. response : 从json格式的响应结果中获取
        # 3. cookies: 保存响应结果的cooies到本地
      - cachefrom: 'body' 
        path: '$.code' 
        name: 'code'
        # 使用方法 需要的地方替换为$caches(code)$
      - cachefrom: 'response' 
        path: '$.data'
        name: 'data'
        # 使用方法 需要的地方替换为$caches(data)$
      - cachefrom: 'cookies' 
        path:  # cookies 时path为空
        name: 'cookies'
        # 使用方法 需要的地方替换为$caches(cookies)$
     
    # 接口关联
    relevance:
    # 判断如果不需要关联relevance字段为空即可
    # 如果需要关联就
        response:
          # 场景 接口A删除请求,需要接口B新增请求中返回的ID以及name
          - relCaseName: pointAdd # 其他testcase的ID
            relCaseNum: 1 # 关联的case数组里 第几条数据
            reldata:
            - value: $.id # 当前返回结果的jsonpath
              name: pointId # 关联值名称
            - value: $.name # 当前返回结果的jsonpath
              name: pointname # 关联值名称
    teardown:
      - tdName: pointDel # 后置请求的caseID
        tdNum: 1 # 后置请求的case数组里 第几条数据
        tddata:
          - datatype: param
            dataname: name
            path: $.name
          - datatype: urlparam
            dataname: pointId
            path: $.id
          - datatype: json
            dataname: name
            path: $.name
        
    # 机制为 根据relevance字段生成字典{"tradeId":"123"} 
    # 使用关联值方法为将需要替换的地方修改为 $relevance(tradeId)$

    headers: {
      "Content-Type": "application/json"
    }
    data:
      file: {
        files: D:\test\test.csv # 上传文件的参数名:文件路径
      }
      param: {
        "username": "finsiot","password": "$caches(pwd)$" # 读取缓存值
      }
      urlparam: {
      id: 123
      }# 路径参数 v1/api/$url(id)$/
    assert:
      jsonpath:
        - {
          "path": "$.data.expense_trend[0].peak_hour.peak_hour",
          "value": "123", 
          "asserttype": "=="
        }
        - {
          "path": "$.code",
          "value": 0,
          "asserttype": "=="
        }
        - {
          "path": "$.data.id",
          "value": 196,
          "asserttype": "=="
        }
      sqlassert:
      # 如果不需要 此字段置空即可
        - {
          "datas": [
            {
              "path": "$.data.id",
              "name": "id"
            },
            {
              "path": "$.data.username",
              "name": "username"
            },
          ],
          "sql": "select * from saas.user where username = '****'", 
           # 取数据库查询出的第一条数据进行验证 如果存在 列名 username 值为$.data.username则通过
          "db_name": "database" # 判断链接那个数据库
          }
      time: 2 # 响应时间断言
      code: 200 # HTTP响应码断言

3.2 config.ini配置文件格式

重点为[directory] 中的test_name 所有程序都围绕test_name 进行执行 根据testname来生成测试用例执行测试等

[directory] # 路径相关
log_dir = /logs
data_dir = /datas
page_dir = /page
report_xml_dir = /report/xml
report_html_dir = /report/html
test_suite = /test_suite
case_dir = /testcase
cache_dir = /caches
test_name = 测试项目名称: saasWeb
[host]
host = 
[email]
;服务器
mail_host = smtp.sina.com
;发送邮箱
mail_user = 
;口令
mail_pass = 
;发送者
sender = 
;接收邮箱
receivers = 
[database]
host = 192.
port = 3306
user = root
password = 
;database = 
database = 
charset = utf8
[redis]
host = 127.0.0.1
port = 6379
db = 1
password = 123456
charset = UTF-8
[dingding]
webhook = 
secret = 

四、接口录制

1.代理设置
设置计算机代理
http=127.0.0.1:4444;https=127.0.0.1:4444;ftp=127.0.0.1:4444
<-loopback>
HTTPS:
http://mitm.it/ 开启代理后下载证书安装
执行脚本 recording.py 每个请求将会在 ./test_suite/recording 文件夹中建立文件 每次执行录制时会覆盖原文件

五、接口加密(测试版)

加签加密法: 在config中encryption增加sign的值 为签 需要在util.tools.encryption文件内自己编辑加密规则 img_2.png 需要加密的接口 YAML数据中encryption的值为true 会根据此在请求用例前增加加密装饰器 img_1.png

六、操作方法

  1. 新建config/config.ini文件 格式如上例子
  2. 执行util/scripts/newProject.py 根据testname生成测试项目基础目录
  3. 在生成的test_suite/datas/testname 文件夹下增加yaml测试用例
  4. 执行util/scripts/writeCase.py生成测试脚本 关于token 需要根据自己项目情况修改yaml文件中token关键字 如果不需要token值为false 需要token则改为需要的类型
  5. 执行setupMain.py开始测试(单用例调试时需要执行util\tools\readYamlFile.py将测试数据存入redis)

七、代码展示

test_login.py 自动生成吃的测试用例 login.yml 登录接口yaml文件 conftest.py conftests中使用cookie的登录前置

八、jenkins集成

8.1 docker环境搭建:

1 安装docker(不会请百度)
2 新建任意文件夹
3 新建文件 Dockerfile 4 新建文件docker-compose.yml
5 复制python安装包img_3.png 文件内容如下:
docker-compose.yml

version: '3'
services:
  jenkins:
    image: "jenkins_python"
    build: .
    depends_on:
      - redis
    container_name: jenkins
    volumes:
      - "/home/jenkins:/var/jenkins_home"
    ports:
      - "10240:8080"
      - "10241:50000"
    user: root
    links:
      - redis
  redis:
    image: "redis:alpine"
    container_name: redis
    restart: always
    volumes:
      - ../redis/redis.conf:/usr/local/etc/redis/redis.conf:rw
      - ../redis/data:/data:rw
    command: --requirepass "123456"
    ports:
      - "6379:6379"
    expose:
      - 6379

Dockerfile

FROM jenkins/jenkins
USER root
ADD ./Python-3.9.7.tgz /var/python
RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN sed -i s@/security.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list
WORKDIR /var/python3
RUN apt-get update \
&& apt-get install -y vim\
&& apt-get -y install gcc automake autoconf libtool make \
&& apt-get -y install zlib* \
&& apt-get -y install openssl libssl-dev \
&& apt-get -y install sudo \
&& apt-get install libffi-dev \
&& apt-get install -y nodejs \
&& /var/python/Python-3.9.7/configure --prefix=/var/python3 --with-ssl \
&& make \
&& make install \
&& ln -sf /var/python3/bin/python3.9 /usr/bin/python \
&& ln -sf /var/python3/bin/pip3 /usr/bin/pip \
&& apt install npm -y \
&& npm install -g allure-commandline --save-dev \
&& /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
WORKDIR /

在文件目录内执行命令
docker-compose up 这样生成了两个容器 一个是包含allure和python的jenkins容器和一个redis容器

8.2jenkins配置

Javahome路径 查询echo $JAVA_HOME 输出 /opt/java/openjdk

1 安装allure 和gitee插件

2 配置全局变量

img_6.png

3.新建autotest任务

img_7.png

img_8.png

img_9.png

img_10.png

img_11.png

img_12.png 4 增加构建步骤

img_13.png


pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=1000 -r requirements.txt

python setupMain.py

5 增加构建后操作allure报告

img_14.png

report/xml

点击高级

img_15.png

report/html

注意路径 相对workspace内任务的路径 前面没有斜线

###8.3注意事项

注意路径 相对workspace内任务的路径 前面没有斜线
Ubuntu文件编码有坑 项目yaml文档必须用utf-8编码

8.4脚本代码更改

找到setipMain.py img.png
红框内注意为当前jenkins建立的任务名称
修改config.ini内redis配置 配置内容与docker容器保持一致 如密码 img.png

注意 host 为dockercompose内link名称 内部链接采用redis:6379


总结

这里给大家分享出来希望能和朋友们共同学习,共同进步 源码地址 https://gitee.com/a529548204/apitest

空文件

简介

根据yaml自动生成测试用例脚本 支持sql断言 支持参数化 路径参数 支持数据关联 支持多种类随机数据生成 多种正则匹配 跨文件数据 关联支持分布式 使用redis收集测试用例 支持接口数据加密(测试版) 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化