欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

接口自动化框架HttpRunner实践

程序员文章站 2022-06-04 16:18:13
...

1、安装Python(包括配置Python)

2、安装httprunner

pip install httprunner

接口自动化框架HttpRunner实践

3、生成脚手架

hrun --startproject petstore

接口自动化框架HttpRunner实践

4、html格式的swagger文档的访问地址

http://petstore.swagger.io/

5、json格式的swagger文档的访问地址

https://petstore.swagger.io/v2/swagger.json

6、解析json格式的swagger文档,生成自动化用例

接口自动化框架HttpRunner实践

# -*- coding: utf-8 -*-
# @Time    : 2019/9/9 15:17
# @Author  :
# @Site    :
# @File    : swagger.py
# @Software: IDEA


import os
import requests
from httprunner import logger
from lib.processingJson import write_data, get_json


class AnalysisJson:
    """swagger自动生成测试用例"""

    def __init__(self, url):
        self.url = url
        self.interface = {}
        self.case_list = []
        self.tags_list = []
        self.http_suite = {"config": {"name": "", "base_url": "", "variables": {}},
                           "testcases": []}
        self.http_testcase = {"name": "", "testcase": "", "variables": {}}

    def retrieve_data(self):
        """
        主函数
        :return:
        """
        try:
            r = requests.get(self.url + '/v2/swagger.json').json()
            write_data(r, 'data.json')
            # r = get_json('D:\HttpRunner_framework\\testcases\data.json')
        except Exception as e:
            logger.log_error('请求swagger url 发生错误. 详情原因: {}'.format(e))
            return 'error'
        self.data = r['paths']  # 接口数据
        self.url = 'https://' + r['host']
        self.title = r['info']['title']
        self.http_suite['config']['name'] = self.title
        self.http_suite['config']['base_url'] = self.url

        self.definitions = r['definitions']  # body参数
        for tag_dict in r['tags']:
            self.tags_list.append(tag_dict['name'])
        i = 0
        for tag in self.tags_list:
            self.http_suite['testcases'].append({"name": "", "testcase": "", "variables": {}})
            self.http_suite['testcases'][i]['name'] = tag
            self.http_suite['testcases'][i]['testcase'] = 'testcases/' + tag + '.json'
            i += 1

        suite_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)),
                                  'testsuites')
        testcase_path = os.path.join(suite_path, 'demo_testsuite.json')
        write_data(self.http_suite, testcase_path)
        if isinstance(self.data, dict):
            for tag in self.tags_list:
                self.http_case = {"config": {"name": "", "base_url": "", "variables": {}}, "teststeps": []}

                for key, value in self.data.items():
                    for method in list(value.keys()):
                        params = value[method]
                        try:
                            if params['deprecated']:  # 接口是否被弃用
                                logger.log_info(
                                    'interface path: {}, if name: {}, is deprecated.'.format(key, params['description']))
                                break
                        except KeyError:
                            if params['tags'][0] == tag:
                                self.http_case['config']['name'] = params['tags'][0]
                                self.http_case['config']['base_url'] = self.url
                                case = self.retrieve_params(params, key, method, tag)
                                self.http_case['teststeps'].append(case)
                api_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)),
                                        'testcases')
                testcase_path = os.path.join(api_path, tag + '.json')
                write_data(self.http_case, testcase_path)


        else:
            logger.log_error('解析接口数据异常!url 返回值 paths 中不是字典.')
            return 'error'

    def retrieve_params(self, params, api, method, tag):
        """
        解析json,把每个接口数据都加入到一个字典中
        :param params:
        :param params_key:
        :param method:
        :param key:
        :return:
        replace('false', 'False').replace('true', 'True').replace('null','None')
        """
        http_interface = {"name": "", "variables": {},
                          "request": {"url": "", "method": "", "headers": {}, "json": {}, "params": {}}, "validate": [],
                          "output": []}
        http_testcase = {"name": "", "api": "", "variables": {}, "validate": [], "extract": [], "output": []}

        name = params['summary'].replace('/', '_')
        http_interface['name'] = name
        http_testcase['name'] = name
        http_testcase['api'] = 'api/{}/{}.json'.format(tag, name)
        http_interface['request']['method'] = method.upper()
        http_interface['request']['url'] = api.replace('{', '$').replace('}', '')
        parameters = params.get('parameters')  # 未解析的参数字典
        responses = params.get('responses')
        if not parameters:  # 确保参数字典存在
            parameters = {}
        for each in parameters:
            if each.get('in') == 'body':  # body 和 query 不会同时出现
                schema = each.get('schema')
                if schema:
                    ref = schema.get('$ref')
                    if ref:
                        param_key = ref.split('/')[-1]
                        param = self.definitions[param_key]['properties']
                        for key, value in param.items():
                            if 'example' in value.keys():
                                http_interface['request']['json'].update({key: value['example']})
                            else:
                                http_interface['request']['json'].update({key: ''})
            elif each.get('in') == 'query':
                name = each.get('name')
                for key in each.keys():
                    if 'example' in key:
                        http_interface['request']['params'].update({name: each[key]})
        for each in parameters:
            # if each.get('in') == 'path':
            #     name = each.get('name')
            #     for key in each.keys():
            #         if 'example' in key:
            #             http_interface['request']['json'].update({name: each[key]})
            #     else:
            #
            #         http_interface['request']['json'].update({name: ''})
            if each.get('in') == 'header':
                name = each.get('name')
                for key in each.keys():
                    if 'example' in key:
                        http_interface['request']['headers'].update({name: each[key]})
                    else:
                        if name == 'token':
                            http_interface['request']['headers'].update({name: '$token'})
                        else:
                            http_interface['request']['headers'].update({name: ''})
        for key, value in responses.items():
            schema = value.get('schema')
            if schema:
                ref = schema.get('$ref')
                if ref:
                    param_key = ref.split('/')[-1]
                    res = self.definitions[param_key]['properties']
                    i = 0
                    for k, v in res.items():
                        if 'example' in v.keys():
                            http_interface['validate'].append({"eq": []})
                            http_interface['validate'][i]['eq'].append('content.' + k)
                            http_interface['validate'][i]['eq'].append(v['example'])

                            http_testcase['validate'].append({"eq": []})
                            http_testcase['validate'][i]['eq'].append('content.' + k)
                            http_testcase['validate'][i]['eq'].append(v['example'])
                            i += 1
                else:
                    http_interface['validate'].append({"eq": []})
            else:
                http_interface['validate'].append({"eq": []})
        if http_interface['request']['json'] == {}:
            del http_interface['request']['json']
        if http_interface['request']['params'] == {}:
            del http_interface['request']['params']

        api_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)), 'api')
        tags_path = os.path.join(api_path, tag)
        if not os.path.exists(tags_path):
            os.mkdir(tags_path)
        json_path = os.path.join(tags_path, http_interface['name'] + '.json')
        write_data(http_interface, json_path)

        return http_testcase


if __name__ == '__main__':
    AnalysisJson('https://petstore.swagger.io').retrieve_data()

# -*- coding: utf-8 -*-
# @Time    : 2019/9/9 15:18
# @Author  :
# @Site    :
# @File    : processingJson.py
# @Software: IDEA

import json
from httprunner import logger


def get_json(path, field=''):
    """
    获取json文件中的值,data.json和res.json可共用
    :param path:
    :param field:
    :return:
    """
    with open(path, 'r', encoding='utf-8') as f:
        json_data = json.load(f)
        if field:
            data = json_data.get(field)
            return data
        else:
            return json_data


def write_data(res, json_path):
    """
    把处理后的参数写入json文件
    :param res:
    :param json_path:
    :return:
    """
    if isinstance(res, dict) or isinstance(res, list):
        with open(json_path, 'w', encoding='utf-8') as f:
            json.dump(res, f, ensure_ascii=False, sort_keys=True, indent=4)
            logger.log_info('Interface Params Total:{} ,write to json file successfully!\n'.format(len(res)))
    else:
        logger.log_error('{} Params is not dict.\n'.format(write_data.__name__))

7、宠物相关的接口(自动生成的)

接口自动化框架HttpRunner实践

{
    "name": "Add a new pet to the store",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "json": {
            "category": {},
            "id": "",
            "name": "$name",
            "photoUrls": [],
            "status": "$status",
            "tags": []
        },
        "method": "POST",
        "url": "/pet"
    },
    "validate": [],
    "variables": {}
}
{
    "name": "Deletes a pet",
    "output": [],
    "request": {
        "headers": {
            "Accept": "application/json",
            "api_key": ""
        },
        "method": "DELETE",
        "url": "/pet/$id"
    },
    "validate": [],
    "variables": {}
}
{
    "name": "Find pet by ID",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "method": "GET",
        "url": "/pet/$id"
    },
    "validate": [],
    "variables": {}
}
{
    "name": "Finds Pets by status",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "method": "GET",
        "url": "/pet/findByStatus?status=$status"
    },
    "validate": [],
    "variables": {}
}
{
    "name": "Update an existing pet",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "json": {
            "category": {},
            "id": "$petId",
            "name": "$name",
            "photoUrls": [],
            "status": "available",
            "tags": []
        },
        "method": "PUT",
        "url": "/pet"
    },
    "validate": [],
    "variables": {}
}
{
    "name": "Updates a pet in the store with form data",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "method": "POST",
        "url": "/pet/$petId",
        "data": {
            "name": "$name",
            "status": "$status"
        }
    },
    "validate": [],
    "variables": {}
}
{
    "name": "uploads an image",
    "output": [],
    "request": {
        "headers": {"Accept": "application/json"},
        "method": "POST",
        "url": "/pet/$petId/uploadImage",
        "files": {"file": ["pet.jpg","${get_file($filePath)}","image/jpeg"]}
    },
    "validate": [],
    "variables": {}
}

8、自定义函数get_file

# -*- coding: utf-8 -*-
# @Time    : 2019/12/08 17:34
# @Author  : yangzc
# @Site    :
# @File    : debugtalk.py
# @Software: IDEA
import time


def sleep(n_secs):
    time.sleep(n_secs)


# 读取文件内容
def get_file(file_path):
    return open(file_path, "rb")

9、宠物接口的测试用例(自动生成的)

接口自动化框架HttpRunner实践

{
    "config": {
        "base_url": "https://petstore.swagger.io/v2",
        "name": "pet",
        "variables": {}
    },
    "teststeps": [
        {
            "api": "api/pet/Add a new pet to the store.json",
            "extract": [{"id": "content.id"}],
            "name": "Add a new pet to the store",
            "output": [],
            "validate": [],
            "variables": {
                "name": "小猪佩奇",
                "status": "available"
            }
        },
        {
            "api": "api/pet/Find pet by ID.json",
            "extract": [],
            "name": "Find pet by ID",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "content.status",
                        "available"
                    ]
                }
            ],
            "variables": {}
        },
        {
            "api": "api/pet/Finds Pets by status.json",
            "extract": [],
            "name": "Finds Pets by status",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "status_code",
                        200
                    ]
                }
            ],
            "variables": {"status": "sold"}
        },
        {
            "api": "api/pet/uploads an image.json",
            "extract": [],
            "name": "uploads an image",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "status_code",
                        200
                    ]
                }
            ],
            "variables": {
                "petId": "9216678377732767000",
                "filePath": "C:\\Users\\yangzc\\Desktop\\pet.jpg"}
        },
        {
            "api": "api/pet/Update an existing pet.json",
            "extract": [],
            "name": "Update an existing pet",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "status_code",
                        200
                    ]
                },
                {
                    "eq": [
                        "content.name",
                        "喜羊羊"
                    ]
                }
            ],
            "variables": {
                "petId": "9216678377732767000",
                "name": "喜羊羊"}
        },
        {
            "api": "api/pet/Updates a pet in the store with form data.json",
            "extract": [],
            "name": "Updates a pet in the store with form data",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "status_code",
                        200
                    ]
                }
            ],
            "variables": {
                "petId": "9216678377732767000",
                "name": "灰太狼",
                "status": "sold"
            }
        },
        {
            "api": "api/pet/Deletes a pet.json",
            "extract": [],
            "name": "Deletes a pet",
            "output": [],
            "validate": [
                {
                    "eq": [
                        "status_code",
                        200
                    ]
                }
            ],
            "variables": {}
        }
    ]
}

10、自动生成的测试集

{
    "config": {
        "base_url": "https://petstore.swagger.io",
        "name": "Swagger Petstore",
        "variables": {}
    },
    "testcases": [
        {
            "name": "pet",
            "testcase": "testcases/pet.json",
            "variables": {}
        },
        {
            "name": "store",
            "testcase": "testcases/store.json",
            "variables": {}
        },
        {
            "name": "user",
            "testcase": "testcases/user.json",
            "variables": {}
        }
    ]
}

10、运行测试集

hrun .\testsuites\demo_testsuite.json

接口自动化框架HttpRunner实践

11、测试报告

接口自动化框架HttpRunner实践

12、参考资料

[01] HttpRunner中文用户手册
[02] 基于HttpRunner,解析swagger数据,快速生成接口测试框架
[03] 开源啦~接口自动化测试平台
[04] 基于 HttpRunner 的 Web 测试平台:HttpRunnerManager
[05] httprunner学习25-文件上传multipart/form-data
[06] swagger api一键导入postman

微信扫一扫关注公众号
接口自动化框架HttpRunner实践
点击链接加入群聊

https://jq.qq.com/?_wv=1027&k=5eVEhfN
软件测试学习交流QQ群号:511619105

相关标签: httprunner python