目录
目录README.md

接口自动化测试框架 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)

quot; # 读取缓存值 }(同样适用于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)
quot; # 读取缓存值 } 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)
quot; # 267 str_num = '$RandomString($RandomPosInt(2,23)$)$RandomPosInt(1,333)
#39; # AbE3c14580f29aDFe5 float_num = '$RandomFloat($RandomPosInt(2,13)$,$RandomPosInt(2,13)$,$RandomPosInt(2,13)$)
#39; # 11.84864 time_num = '$GetTime(time_type=else,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,0,0)
#39; # 当前时间 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)
#39; # 未来时间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)
#39; # 过去时间3天前 2022-04-11 13:33:24 choice_num = '$Choice($RandomPosInt(2,13)$)
#39; # 6 email = "$faker(email)
quot;# 邮箱 # xkong@example.net idcard = "$faker(idcard)
quot; # 130802196003197594 province = "$faker(province)
quot; # 新疆维吾尔自治区 city = "$faker(city)
quot; # 鹏市 phone_number = "$faker(phone_number)
quot; # 15070673645 name = "$faker(name)
quot; # 许云

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)
quot; # 读取缓存值 } 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收集测试用例 支持接口数据加密(测试版)

813.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

©Copyright 2023 CCF 开源发展委员会
Powered by Trustie& IntelliDE 京ICP备13000930号