This article is participating in Python Theme Month. See the link to the event for more details

A,HTTPRUNNERThe open source project

The current framework has been updated to3.X version; Has moved closer to the PyTest testing framework and inherited its related features and benefits.Copy the code
  • But its advantages, in some people’s eyes, also have ‘defects’
For example, it supports the test suite of capturing and exporting HAR data file har2Case into JSON/YAML format; Manual editing and maintenance of test cases in JSON/YAML format is also supported; However, in the face of interface documents, more interfaces need to do interface testing or integration is slightly insufficient, the manual cost of manpower is large, and the efficiency is not high, is there any way to improve? Therefore, the development and the framework of a relatively high fit parsing interface document tools, both support JSON/YAML format and can output Excel documents, convenient and more flexible development and testing framework.Copy the code
  • Let’s first install the environment, and then step by step complete your own requirements
// Don't use the 3.x version of it for now
pip install -y httprunner==2.13.
Copy the code
  • Validation environment: hrun-h, equivalent to Httprunner -h

Develop parsing swagger scripts

  • First install the python libraries required by the environment
// You can write to the requirements. TXT file: PIP install -r requirements. TXT
openpyxl==3.04.
requests==2.24. 0
xlwt==1.3. 0
xlrd==1.2. 0
PyYAML==5.41.
Copy the code
  • Development tools and engineering structures
    • Pycharm is a development tool for Python engineers
    • The screenshot of the engineering structure is as follows:

  • Note to configure the config.ini configuration file in the properties/ directory, you need to fill in the address of the interface document that you have parsed
[swaggerUrl] # Swagger interface document address baseSever_url = http://localhost:8090Copy the code
Example: Deploy a Swagger project yourself to demonstrate the effect
  • The effect is as follows:

  • But we don’t want a UI, we want an interface, so F12 opens

    • To get the interface address and write config. Ini configuration file: http://localhost:8090/v2/api-docs

Third, skip the development process to see the effect demonstration

Script design ideas: 1, not only to conform to httprunner framework support JSON/YAML use cases, but also to support Excel output 2, this idea is mainly from the crawler, crawling interface response data to parse and reassemble the outputCopy the code
Script core code, moreCheck it out on Github
  • Cleaning data function
    def wash_params(self, params, api, method, tag) :
        Param params: :param params_key: :param method: :param key: :return: param params_key: :param method: :param key: :return: replace('false', 'False').replace('true', 'True').replace('null','None') """
        # Define the interface data format
        http_interface = {"name": ""."variables": {},
                          "request": {"url": ""."method": ""."headers": {}, "json": {}, "params": {}}, "validate": []."output": []}
        # Test case data format:
        http_api_testcase = {"name": ""."api": ""."variables": {},"validate": []."extract": []."output": []}

        # Here the problem needs to be specific to analyze, development sometimes outline using other symbols to split /// split symbols need to be replaced
        case_name = params['summary']#.replace('/', '_').replace(" ", "_").replace(":", "_")
        case_name=re_pattern(case_name)
        # Use case name
        http_interface['name'] = case_name
        http_api_testcase['name'] = case_name
        # This is the name written under testCasejson, not the directory where the API was generated
        http_api_testcase['api'] = 'api/{}/{}.json'.format(tag, case_name)
        Capitalize all methods
        http_interface['request'] ['method'] = method.upper()
        # This is an alternative to the /get request concatenation in the URI. Parameter =& parameter concatenation, which requires additional parsing
        http_interface['request'] ['url'] = api.replace(
            '{'.'$').replace('} '.' ')
        parameters = params.get('parameters')    # Unresolved request parameter
        responses = params.get('responses')    # Unresolved response parameter
        if not parameters:    Make sure the parameter dictionary exists
            parameters = {}
            
        Add parsed parameters to the test case dictionary
        for each in parameters:
            if each.get('in') = ='body':    # body and query do not appear together
                schema = each.get('schema')
                if schema:
                    ref = schema.get('$ref')
                    if ref:
                        # This uri is split to take the number of/backslashes
                        param_key = ref.split('/'.2)[-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: ' '})
            
            # Actual request method or request parameter format
            elif each.get('in') = ='query':
                name = each.get('name')
                for key in each.keys():
                    if not 'example' in key:    Write the json test case to the query argument
                        http_interface['request'] ['params'].update({name: each[key]})
        
        Parse interface document request parameters
        for each in parameters:
            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: ' '})
                                
        # Parse interface document response parameters
        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_api_testcase['validate'].append({"eq": []})
                            http_api_testcase['validate'][i][
                                'eq'].append('content.' + k)
                            http_api_testcase['validate'][
                                i]['eq'].append(v['example'])
                            i += 1
                else:
                    if len(http_interface['validate']) != 1:
                        http_interface['validate'].append({"eq": []})
            else:
                if len(http_interface['validate']) != 1:
                    http_interface['validate'].append({"eq": []})
        
        If the assertion is null, the HTTP state assertion is added by default
        if http_interface.get("validate"):
            http_interface.get("validate") [0].update({"eq": ["status_code".200]})
        
        If the test case has an empty dictionary as its request parameter, remove these keys
        if http_interface['request'] ['json'] = = {} :del http_interface['request'] ['json']
        if http_interface['request'] ['params'] = = {} :del http_interface['request'] ['params']
        # Define interface test cases
        tags_path = os.path.join(case_dir, tag).replace("/"."_").replace(""."_")
        # Create a directory that does not exist, recursively
        if not os.path.exists(tags_path):
            os.makedirs(tags_path)
            
        # Concatenate API use case paths
        json_path = os.path.join(tags_path, case_name + '.json')
        # testcases/ Write data
        write_data(http_interface, json_path)
        
        return http_api_testcase
Copy the code
  • Enter the script and execute the program entry
if __name__ == '__main__':
    url = conf.get_value("swaggerUrl"."baseSever_url")
    js = AnalysisSwaggerJson(url)
    js.analysis_json_data(isDuplicated=False)
    js.write_excel(url, handlefile.get_file_list(case_dir))
Copy the code
  • The resulting output is shown in the figure

  • Is it the best of both worlds to have both JSON and excel files?
First, improve the test case in the API/directory:
  • Complete the interface input parameters, as shown in the figure

  • Go to the swagger use case directory and run :hrun testCases user-related interface. Json, log:

  • And generate HTML test report, open as shown in figure:

  • Isn’t that very nice
While generating JSON/YAML conforms to httprunner test framework; While generating Excel, you can develop your own custom automated test framework.Copy the code

Swagger Tool summary

  • Let’s introduce a wave of Httprunner_Swagger gadgets. There are already 19 stars, but we still need you.
  • Welcome to put forward different optimization suggestions, if combined with other testing frameworks, make a strong third party open source library, to serve more people, it would be a beautiful thing!