行为驱动开发 behave 接口测试demo

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

你可能感兴趣的:(数据库,java,json)