behave 接口测试,可以使接口测试简单化,并且使接口做流程非常容易
behave的具体使用就不介绍了
展示一下feature
Feature:订单流程:登录、搜索商品、加入购物车、提交订单、支付、生成物流
Scenario:常规下单流程
Given 初始化数据
When 登录 userName: "behave" password:"behave"
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.result | bool | eq | True |
Then 处理JWT token
When 搜索商品
"""
{"name":"product1"}
"""
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.result | bool | eq | True |
| json | $.value[0].id | int | gt | 2 |
| json | $.value[0].name | str | contains | product1 |
| json | $.value[0].productImage | None| eq | None |
| json | $.value | list | eq | [{"id": 1, "name": "product1", "productImage": null}, {"id": 2, "name": "product1", "productImage": null}] |
Then 提取Json响应数据
| json_path | save_as |
| $.value[0].id | product_id |
When 加入购物车
"""
${product_id}
"""
Then 验证响应状态码
"""
200
"""
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.value[0].product_id| list | eq | ${product_id} |
Then 提取Json响应数据
| json_path | save_as |
| $.value[0].cart_id | cart_id |
When 提交订单
"""
${cart_id}
"""
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.value[0].cart_id | list | eq | ${cart_id} |
Then 提取Json响应数据
| json_path | save_as |
| $.value[0].order_id | order_id |
When 支付订单
"""
${order_id}
"""
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.value[0].order_id | list | eq | ${order_id} |
When 生成物流单
"""
${order_id}
"""
Then 验证响应状态码
"""
200
"""
Then 验证响应数据
| type | json_path | value_type | operater | expect_value |
| json | $.value[0].order_id | list | eq | ${order_id} |
包括请求构建与发送,返回值提取与保存,assert
环境统一管理,在environment.py的before_all进行统一处理
'dev': {
'hosts': {
'login': 'http://localhost:6100/login',
'product': 'http://localhost:6100/api/product',
'cart': 'http://localhost:6100/api/cart',
'order': 'http://localhost:6100/api/order',
'pay': 'http://localhost:6100/api/pay',
'user': 'http://localhost:6100/api/user',
'logistics': 'http://localhost:6100/api/logistics',
}
},
业务层面的step在单独py文件进行编写
登录是表单提交,requests的content-type需要修改
@when(u'登录 userName: "{userName}" password:"{password}"')
def step_impl(context, userName, password):
method = "post"
url = context.hosts['login']
js = {'userName': userName, 'password': password}
logging.info(f"登录json数据.{js}")
headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
}
context.headers.update(headers)
context.response = context.session.request(method, url, data=js, headers=context.headers)
请求后处理放在统一的文件编写
def step_impl(context):
jsn = context.response.json()
if "token" not in jsn.keys():
logging.error("response中不存在token")
raise AttributeError
else:
token = jsn["token"]
context.headers["Authorization"] = f"Bearer {token}"
@then(u"删除headers中的key")
def step_impl(context):
if not context.text:
return
if context.text in context.hearders.keys():
context.headers.pop(context.text)
@then(u'提取Json响应数据')
def step_impl(context):
if context.text:
return
elif context.table:
for row in context.table:
save_as = row.get('save_as')
json_path = row.get('json_path')
actual_value = get_json_path_value(context.response.json(), json_path)[0]
context.restore_params[save_as] = actual_value
logging.info(f"提取Json响应数据{save_as}: {json_path} = {actual_value}")
else:
logging.error("context.text 或 context.table需要数据")
raise ValueError
运行日志
2023-05-25 07:39:48.000+0800 environment.py[line:79] INFO before_feature-------features/f1/example.feature----订单流程:登录、搜索商品、加入购物车、提交订单、支付、生成物流
2023-05-25 07:39:48.000+0800 environment.py[line:95] INFO before_scenario---------scenario: 常规下单流程
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----初始化数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 business_api.py[line:23] INFO 登录json数据.{'userName': 'behave', 'password': 'behave'}
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----登录 userName: "behave" password:"behave"------Status.passed------duration:0.016s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.result True operator_key eq actual_value True
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value True operator_key eq actual_value True
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----处理JWT token------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 business_api.py[line:43] INFO get product list:{'error': None, 'result': True, 'value': [{'id': 1, 'name': 'product1', 'productImage': None}, {'id': 2, 'name': 'product1', 'productImage': None}]}
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----搜索商品------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.result True operator_key eq actual_value True
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value True operator_key eq actual_value True
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].id 2 operator_key gt actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value 2 operator_key gt actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].name product1 operator_key contains actual_value product1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value product1 operator_key contains actual_value product1
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].productImage None operator_key eq actual_value None
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value None operator_key eq actual_value None
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value [{"id": 1, "name": "product1", "productImage": null}, {"id": 2, "name": "product1", "productImage": null}] operator_key eq actual_value [{'id': 1, 'name': 'product1', 'productImage': None}, {'id': 2, 'name': 'product1', 'productImage': None}]
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value [{'id': 1, 'name': 'product1', 'productImage': None}, {'id': 2, 'name': 'product1', 'productImage': None}] operator_key eq actual_value [{'id': 1, 'name': 'product1', 'productImage': None}, {'id': 2, 'name': 'product1', 'productImage': None}]
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.016s
2023-05-25 07:39:48.000+0800 handle_response.py[line:164] INFO 提取Json响应数据product_id: $.value[0].id = 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----提取Json响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 business_api.py[line:55] INFO 加入购物车json数据.{'product_id': 1, 'count': 2}
2023-05-25 07:39:48.000+0800 business_api.py[line:61] INFO response of post cart:{'error': None, 'result': True, 'value': [{'cart_id': 1, 'count': 2, 'product_id': 1, 'time': 1684971588.6957045}]}
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----加入购物车------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:54] INFO Assert: expect_value 200 operator_key eq actual_value 200
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应状态码------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].product_id ${product_id} operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value 1 operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:164] INFO 提取Json响应数据cart_id: $.value[0].cart_id = 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----提取Json响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 business_api.py[line:73] INFO 提交订单json数据.{'cart_id': 1, 'count': 2}
2023-05-25 07:39:48.000+0800 business_api.py[line:79] INFO response of post order:{'error': None, 'result': True, 'value': [{'cart_id': 1, 'name': 'product1', 'order_id': 1, 'time': 1684971588.6957045}]}
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----提交订单------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].cart_id ${cart_id} operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value 1 operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.016s
2023-05-25 07:39:48.000+0800 handle_response.py[line:164] INFO 提取Json响应数据order_id: $.value[0].order_id = 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----提取Json响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 business_api.py[line:91] INFO 提交订单json数据.{'order_id': 1}
2023-05-25 07:39:48.000+0800 business_api.py[line:97] INFO response of post order:{'error': None, 'result': True, 'value': [{'cart_id': 1, 'name': 'product1', 'order_id': 1, 'time': 1684971588.7112796}]}
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----支付订单------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].order_id ${order_id} operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value 1 operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----生成物流单------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 handle_response.py[line:120] INFO $.value[0].order_id ${order_id} operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 handle_response.py[line:70] INFO Assert: expect_value 1 operator_key eq actual_value 1
2023-05-25 07:39:48.000+0800 environment.py[line:66] INFO after_step-------features/f1/example.feature----验证响应数据------Status.passed------duration:0.000s
2023-05-25 07:39:48.000+0800 environment.py[line:105] INFO after_scenario-----scenario: 常规下单流程 ---Status.passed---duration:0.047s
2023-05-25 07:39:48.000+0800 environment.py[line:85] INFO after_feature-------features/f1/example.feature----订单流程:登录、搜索商品、加入购物车、提交订单、支付、生成物流------Status.passed------duration:0.047s
使用Flask简单mock的接口脚本
@app.route('/login', methods=['POST', "GET"])
def user():
if request.method == 'POST':
userName = request.form['userName']
password = request.form['password']
if userName == 'behave' and password == 'behave':
session['username'] = userName
return { "result": True, "error": None, "token": generate_token(userName)}
else:
return { "result": True, "error": 'the username or userpwd does not match!'}
return {"result": True, "error": None}
@app.route('/api/product', methods=['POST', "GET"])
def product():
print("-------session.keys-", session.keys())
if request.method == "GET":
if request.args.get("name") == "product1":
result = {
"result": True,
"error": None,
"value": [
{
"id": 1,
"name": "product1",
"productImage": None
},
{
"id": 2,
"name": "product1",
"productImage": None
}
]
}
return result
return {"result": True, "error": None, "value": []}
return {"result": True, "error": None, "value": "Done"}
@app.route('/api/order', methods=['POST', "GET"])
def order():
cart_id = request.json.get('cart_id', "")
result = {
"result": True,
"error": None,
"value": [
{
"order_id": 1,
"cart_id": cart_id,
"name": "product1",
"time": time.time()
}
]
}
return result
@app.route('/api/cart', methods=['POST', "GET"])
def cart():
product_id = request.json.get('product_id', "")
count = request.json.get('count', 1)
print("-----cart---", request.args.keys(), request.form.keys(), product_id)
result = {
"result": True,
"error": None,
"value": [
{
"cart_id": 1,
"product_id": product_id,
"count": count,
"time": time.time()
}
]
}
return result
@app.route('/api/pay', methods=['POST', "GET"])
def pay():
order_id = request.json.get('order_id', 0)
result = {
"result": True,
"error": None,
"value": [
{
"order_id": order_id,
"cart_id": 1,
"name": "product1",
"time": time.time()
}
]
}
return result
@app.route('/api/logistics', methods=['POST', "GET"])
def logistics():
print("----logistics----", request.args)
order_id = request.json.get('order_id', 0)
result = {
"result": True,
"error": None,
"value": [
{
"order_id": order_id,
"name": "product1",
"time": time.time()
}
]
}
return result