Python3接口自动化测试

2,088 阅读5分钟

前言

做为开发人员,测试这个领域很少触及,但是最近心血来潮,想了解一下自动化测试,然后就先从接口测试开始了。本人是java党,py刚入门,代码写得很粗糙,忘各位大神多多指点。

准备工作

本文以登录接口为例。

接口文档

  • 用户登录

请求URL:

  • {{baseUrl}}/ums/user/login

请求方法:

  • POST

请求头

  • application/json

请求参数:

参数名 必选 类型 说明
userName string 用户名
password string 密码

参数样例

{
    "userName": "admin",
    "password": "666666"
}

返回样例

{
  "msg": "ok",
  "code": 0,
  "data": {
    "userId": "1",
    "userName": "mldong",
    "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHQiOiJ7fSIsImlzcyI6Im1vbGUiLCJjaGFubmVsIjoiYWRtaW4iLCJleHAiOjE1ODg1MTIyNzUsImlhdCI6MTU4ODUwODY3NSwidXNlcklkIjoiMSIsInVzZXJuYW1lIjoibWxkb25nIn0.2AixzH5Dy_I11Rla4uylhxsMQIBYVDn9eYLK619d9u0"
  }
}

状态码说明

状态码 说明
0 成功
81009001 用户不存在
81009002 用户名或密码错误
81009003 登录次数太多
81009004 用户已被锁定
99990001 参数不合法

用例文档

测试用例编写参考于接口文档,接口自动化也是基于测试用例,所以在做接口自动化前,就得先制定测试用例文档模板。

id name description url method data contentType rule expectedResult
L001 登录 用户名密码正确 ums/user/login post {
"userName":"mldongdemo",
"password":"mldongdemo"
}
application/json default 0
L002 登录 用户不存在 ums/user/login post {
"userName":"mldong6666",
"password":"mldongdemo"
}
application/json default 81009001
L003 登录 用户名或密码错误 ums/user/login post {
"userName":"mldongdemo",
"password":"mldong6666"
}
application/json default 81009002
L004 登录 登录次数太多 ums/user/login post {
"userName":"mldongdemo",
"password":"mldong6666"
}
application/json default 81009003
L005 登录 用户已被锁定 ums/user/login post {
"userName":"mldongdemo",
"password":"mldongdemo"
}
application/json default 81009004
L006 登录 参数不合法 ums/user/login post {
"userName":"5599090",
"password":"mldong"
}
application/json default 99990001

用例模板说明

属性 说明
id 用例编号
name 用例名称
description 用例说明
url 请求地址
method 请求方法
data 请求参数
contentType 请求类型
rule 校验规则
expectedResult 预期结果(状态码)

处理流程

  • 第一步:加载配置信息
  • 第二步:读取用例模板数据
  • 第三步:构造请求参数
  • 第四步: 发送接口请求
  • 第五步:解析接口返回内容
  • 第六步:使用校验规则,输出检验结果
  • 第七步:组装测试结果数据
  • 第八步:生成测试报告

开始编码

工程目录

├── config
	└── app.yml      # 配置文件
├── usecase			 # 测试用例目录
	├── login.yml	 # yaml定义的测试用例
	└── login.xlsx	 # xlsx定义的测试用例
├── templates        # 测试报告模板目录
	└── index.html   # 测试报告模板
├── testport		 # 测试报告目录
    └── result.html	 # 测试报告
├── main.py          # py脚本
└── requirements.txt # 依赖库

config/app.yml

# 工程名称
name: moletest
# 工程说明
description: 接口自动化测试
# 版本号
version: V1.0
usecaseType: yaml # 用例类型(yaml/xlsx)
# 测试用例目录(暂时不处理,使用绝对路径)
usecaseDir:  F:\\mldong\\python-workspace\\test\\usecase
# 测试报告目录(暂时不处理,使用绝对路径)
testreport: F:\\mldong\\python-workspace\\test\\testreport
baseUrl: http://demo.mldong.com/api/

usecase/login.yml

usecaseList:
  - id: L00001               # 用例编号
    name: 登录               # 用例名称
    description: 用户名密码正确  # 用例说明
    url: ums/user/login      # 接口地址
    method: post              # 请求方法
    data: '{"userName": "mldong","password":"mldong@666"}' # 请求参数
    contentType: application/json                         # 参数类型
    rule: default    # 校验规则
    expectedResult: 0    # 预期结果code=0
  - id: L00002               # 用例编号
    name: 登录               # 用例名称
    description: 用户名密码错误  # 用例说明
    url: ums/user/login      # 接口地址
    method: post              # 请求方法
    data: '{"userName": "mldong","password":"123456666"}' # 请求参数
    contentType: application/json                         # 参数类型
    rule: default   # 校验规则
    expectedResult: 81009002   # 预期结果code=81009002

usecase/login.xlsx

略。可参考用例模板制作

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试报告</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<table class="table">
    <tr>
        <th>用例编号</th>
        <th>用例名称</th>
        <th>用例说明</th>
        <th>接口地址</th>
        <th>请求参数</th>
        <th>测试结果</th>
    </tr>
    {% for item in data %}
    <tr>
        <td>{{ item['id'] }}</td>
        <td>{{ item['name'] }}</td>
        <td>{{ item['description'] }}</td>
        <td>{{ item['url'] }}</td>
        <td>{{ item['data'] }}</td>
        <td>{{ item['result'] }}</td>
    </tr>
    {% endfor %}
</table>

</body>
</html>

requirements.txt

certifi==2020.4.5.1
chardet==3.0.4
idna==2.9
Jinja2==2.11.2
MarkupSafe==1.1.1
numpy==1.18.3
pandas==1.0.3
python-dateutil==2.8.1
pytz==2020.1
PyYAML==5.3.1
requests==2.23.0
six==1.14.0
urllib3==1.25.9
xlrd==1.2.0
xlwt==1.3.0

main.py

import requests,yaml,os,json
from jinja2 import FileSystemLoader,Environment
import pandas as pd
def loadConfig():
    """
    加载配置信息
    """
    with open('config/app.yml','r',encoding='utf-8') as f:
        config = yaml.load(f,Loader=yaml.FullLoader)
    return config
def loadYamlUsecase(config):
    """
    加载yaml用例
    """
        res = []
        dir = config['usecaseDir']
        for root,dirs,files in os.walk(dir):
            for file in files:
                if os.path.splitext(file)[1] in ['.yaml','.yml']:
                    with open(os.path.join(root,file),'r',encoding="utf-8") as f:
                        config = yaml.load(f,Loader=yaml.FullLoader)
                        usecaseList = config['usecaseList']
                        for item in usecaseList:
                            res.append(item)
        return res
def loadXlsxUsecase(config):
    """
    加载excel用例
    """
    res = []
    dir = config['usecaseDir']
    for root,dirs,files in os.walk(dir):
            for file in files:
                if os.path.splitext(file)[1] in ['.xlsx']:
                    df = pd.read_excel(os.path.join(root,file))
                    data = df.to_dict('records')
                    for item in data:
                        res.append(item)
    return res
def processUsecase(usecase,config):
    """
    执行测试用例-单个
    """
    res = usecase
    headers = {"Content-Type": usecase["contentType"]}
    baseUrl = config['baseUrl']
    url = usecase['url']
    if url.startswith('http') == False:
    	url = baseUrl+url
    data = usecase['data']
    r = requests.post(url,data=data,headers=headers)
    body = r.text
    print(f"请求地址:{r.url}")
    print(f"请求头:{r.headers}")
    print(f"请求体:{r.request.body}")
    print(f"响应时间:{r.elapsed.total_seconds()}s")
    print(f"返回结果:{r.text}")
    bodyJson = json.loads(body)
    res['result']=bodyJson['code'] == usecase['expectedResult']
    res['body']=body
    res['totalSeconds']=r.elapsed.total_seconds()
    return res
def processUsecaseList(usecaseList,config):
    """
    执行测试用例-遍历
    """
    res = []
    for usecase in usecaseList:
        res.append(processUsecase(usecase,config))
    return res
def buildTestReport(data,config):
    """
    生成测试报告
    """
    env = Environment(loader=FileSystemLoader('templates'))
    template = env.get_template('index.html')
    html = template.render({
        "data": reportData
    })
    with open(config['testreport']+"/result.html", 'w',encoding="utf-8") as f:
        f.write(html)
    return 1
if __name__ == '__main__':
    config = loadConfig()
    usecaseType = config['usecaseType']
    usecaseList = []
    if usecaseType == 'yaml':
        usecaseList = loadYamlUsecase(config)
    elif usecaseType == 'xlsx':
        usecaseList = loadXlsxUsecase(config)
    else:
        print("用例不存在或不支持此类型")
    if len(usecaseList) == 0:
        print("用例不存在")
    else:
        reportData = processUsecaseList(usecaseList,config)
        buildTestReport(reportData,config)

执行命令

python main.py

常用命令说明

  1. 安装指定库
pip3 install requests -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
  1. 生成依赖
pip3 freeze  > requirements.txt 
  1. 安装依赖
pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

源码地址