$ pip install httprunner==2.3.0
$ hrun --startproject demo
Start to create new project: demo
CWD: /Users/zhongxin/PycharmProjects/learn_httprunner
created folder: demo
created folder: demo/api
created folder: demo/testcases
created folder: demo/testsuites
created folder: demo/reports
created file: demo/api/demo_api.yml
created file: demo/testcases/demo_testcase.yml
created file: demo/testsuites/demo_testsuite.yml
created file: demo/debugtalk.py
created file: demo/.env
created file: demo/.gitignore
最小单元,单个接口的操作
一个测试点,多个接口依次调用
测试套,执行多个测试点
测试报告存放路径
环境配置文件
使用python代码进行一些自定义操作
git 版本管理提交时忽略的文件或文件夹
项目结构
先写一个简单的接口
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
right_u_p = {
"username": "测试游记",
"password": "123456"
}
@app.route('/login', methods=['POST'])
def login():
data = json.loads(request.data.decode())
if data.get('username') == right_u_p['username'] and data.get('password') == right_u_p['password']:
return jsonify({"Data": "账号密码正确"}), 200
else:
return jsonify({"Data": "账号密码错误"}), 401
if __name__ == '__main__':
app.run()
在demo/api
中编写第一个登陆的接口测试login.yml
name: 登陆接口
variables:
var1: value1
var2: value2
request:
url: http://127.0.0.1:5000/login
method: POST
headers:
Content-Type: "application/json"
json:
username: "测试游记"
password: "123456"
validate:
- eq: ["status_code", 200]
运行
$ hrun /Users/zhongxin/PycharmProjects/learn_httprunner/demo/api/login.yml
单个接口
运行报告
运行报告
运行详情
查看详情
修改demo/.env
USERNAME=测试游记
PASSWORD=123456
name: 登陆接口
variables:
var1: value1
var2: value2
request:
url: http://127.0.0.1:5000/login
method: POST
headers:
Content-Type: "application/json"
json:
username: ${ENV(USERNAME)}
password: ${ENV(PASSWORD)}
validate:
- eq: ["status_code", 200]
name: 登陆接口
variables:
uname: "测试游记"
pwd: "123456"
request:
url: http://127.0.0.1:5000/login
method: POST
headers:
Content-Type: "application/json"
json:
username: $uname
password: $pwd
validate:
- eq: ["status_code", 200]
在variables
中定义
使用$变量名
在demo/debugtalk.py
中编写获取随机user_agent的函数
def get_user_agent():
user_agent = [
"Mozilla/5.0 ce",
"Mozilla/5.0 shi",
"Mozilla/5.0 you",
"Mozilla/5.0 ji",
]
return random.choice(user_agent)
在login.yml
中使用
name: 登陆接口
variables:
uname: "测试游记"
pwd: "123456"
request:
url: http://127.0.0.1:5000/login
method: POST
headers:
Content-Type: "application/json"
User-Agent: ${get_user_agent()}
json:
username: $uname
password: $pwd
validate:
- eq: ["status_code", 200]
提取url路径
name: 登陆接口
variables:
uname: "测试游记"
pwd: "123456"
base_url: http://127.0.0.1:5000
request:
url: /login
method: POST
headers:
Content-Type: "application/json"
User-Agent: ${get_user_agent()}
json:
username: $uname
password: $pwd
validate:
- eq: ["status_code", 200]
查看httprunner的源码:./site-packages/httprunner/validator.py
从get_uniform_comparator
可以看出它支持的断言以及其简写方式
def get_uniform_comparator(comparator):
""" convert comparator alias to uniform name
"""
if comparator in ["eq", "equals", "==", "is"]:
return "equals"
elif comparator in ["lt", "less_than"]:
return "less_than"
elif comparator in ["le", "less_than_or_equals"]:
return "less_than_or_equals"
elif comparator in ["gt", "greater_than"]:
return "greater_than"
elif comparator in ["ge", "greater_than_or_equals"]:
return "greater_than_or_equals"
elif comparator in ["ne", "not_equals"]:
return "not_equals"
elif comparator in ["str_eq", "string_equals"]:
return "string_equals"
elif comparator in ["len_eq", "length_equals", "count_eq"]:
return "length_equals"
elif comparator in ["len_gt", "count_gt", "length_greater_than", "count_greater_than"]:
return "length_greater_than"
elif comparator in ["len_ge", "count_ge", "length_greater_than_or_equals", \
"count_greater_than_or_equals"]:
return "length_greater_than_or_equals"
elif comparator in ["len_lt", "count_lt", "length_less_than", "count_less_than"]:
return "length_less_than"
elif comparator in ["len_le", "count_le", "length_less_than_or_equals", \
"count_less_than_or_equals"]:
return "length_less_than_or_equals"
else:
return comparator
查看返回信息中的字段
name: 登陆接口
variables:
uname: "测试游记"
pwd: "123456"
base_url: http://127.0.0.1:5000
request:
url: /login
method: POST
headers:
Content-Type: "application/json"
User-Agent: ${get_user_agent()}
json:
username: $uname
password: $pwd
validate:
- eq: ["status_code", 200]
- eq: ["content.Data", "账号密码正确"]
为了测试连续多个步骤
场景:登陆后获取项目信息
修改接口代码
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
right_u_p = {
"username": "测试游记",
"password": "123456"
}
@app.route('/login', methods=['POST'])
def login():
data = json.loads(request.data.decode())
if data.get('username') == right_u_p['username'] and data.get('password') == right_u_p['password']:
return jsonify({"Data": "账号密码正确", "token": "123456"}), 200
else:
return jsonify({"Data": "账号密码错误"}), 401
@app.route('/projects')
def project():
print(request.headers.get("Authorization"))
if request.headers.get("Authorization") == '123456':
return jsonify({"Data": []}), 200
else:
return jsonify({"Data": []}), 401
if __name__ == '__main__':
app.run()
demo/api/get_project_list.yml
name: 获取项目信息
variables:
token: "xxxxx"
base_url: http://127.0.0.1:5000
request:
url: /projects
method: GET
headers:
Content-Type: "application/json"
Authorization: $token
validate:
- eq: ["status_code", 200]
demo/testcases/get_project.yml
可以直接使用已经编写好的接口yaml文件当作步骤
config:
name: "获取项目信息"
variables:
username: ${ENV(USERNAME)}
password: ${ENV(PASSWORD)}
base_url: "http://127.0.0.1:5000"
teststeps:
-
name: 登陆
api: api/login.yml
extract:
- token: content.token
-
name: 获取项目列表信息
api: api/get_project_list.yml
单个接口demo/api/login.yml
name: 登陆接口
variables:
uname: "测试游记"
pwd: "123456"
base_url: http://127.0.0.1:5000
request:
url: /login
method: POST
headers:
Content-Type: "application/json"
User-Agent: ${get_user_agent()}
json:
username: $uname
password: $pwd
validate:
- eq: ["status_code", 200]
- eq: ["content.Data", "账号密码正确"]
参数不固定的接口测试demo/testcases/login.yml
缺少参数:
config:
name: "登陆接口配置"
base_url: "http://127.0.0.1:5000"
teststeps:
-
name: $title
api: api/login.yml
validate:
- eq: ["status_code", $status_code]
- eq: ["content.Data", $content_data]
参数遍历的测试套demo/testsuites/login.yml
config:
name: "接口套件"
testcases:
- name: "登陆接口套件"
testcase: testcases/login.yml
parameters:
- title-uname-pwd-status_code-content_data:
- ["正常登陆","测试游记","123456",200,"账号密码正确"]
- ["账号错误","测试游记1","",401,"账号密码错误"]
- ["密码错误","测试游记","1234567",401,"账号密码错误"]
- ["账号为空","","1234567",401,"账号密码错误"]
- ["密码为空","测试游记","",401,"账号密码错误"]
测试报告
新建demo/datas/account.csv
title,uname,pwd,status_code,content_data
正常登陆,测试游记,123456,200,账号密码正确
账号错误,测试游记1,,401,账号密码错误
密码错误,测试游记,1234567,401,账号密码错误
账号为空,,1234567,401,账号密码错误
密码为空,测试游记,,401,账号密码错误
config:
name: "接口套件"
testcases:
- name: "登陆接口套件"
testcase: testcases/login.yml
parameters:
- title-uname-pwd-status_code-content_data: ${P(datas/account.csv)}
使用csv会出现str和int类型比较的问题,需要在demo/debugtalk.py
编写代码解决
from httprunner.api import HttpRunner
httpruner = HttpRunner()
httpruner.run(r'/Users/zhongxin/PycharmProjects/learn_httprunner/demo/testsuites/login.yml')
print(httpruner.summary)