├── .gitignore ├── .travis.yml ├── LICENSE ├── Pipfile ├── README.md ├── main.py ├── postman2case ├── __init__.py ├── cli.py ├── compat.py ├── core.py └── parser.py ├── setup.py └── tests ├── __init__.py ├── data ├── test.json ├── test_get.json └── test_post.json └── test_postmanparser.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | - 2.7 5 | - 3.4 6 | - 3.5 7 | - 3.6 8 | install: 9 | - pip install pipenv==11.10.0 10 | - pipenv install --dev 11 | script: 12 | - pipenv run python setup.py install 13 | - pipenv run coverage run --source=postman2case -m unittest discover 14 | after_success: 15 | - pipenv run coveralls -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 HttpRunner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | 8 | [dev-packages] 9 | coverage = "*" 10 | coveralls = "*" 11 | twine = "*" 12 | 13 | [scripts] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # postman2case 2 | 3 | [![LICENSE](https://img.shields.io/github/license/HttpRunner/postman2case.svg)](https://github.com/HttpRunner/postman2case/blob/master/LICENSE) [![Build Status](https://travis-ci.org/HttpRunner/postman2case.svg?branch=master)](https://travis-ci.org/HttpRunner/postman2case) [![coveralls](https://coveralls.io/repos/github/HttpRunner/postman2case/badge.svg?branch=master)](https://coveralls.io/github/HttpRunner/postman2case?branch=master) 4 | 5 | Convert postman data to JSON testcases for HttpRunner. 6 | 7 | ## usage 8 | 9 | To see ``postman2case`` version: 10 | 11 | ```shell 12 | $ python main.py -V 13 | 0.0.1 14 | ``` 15 | 16 | To see available options, run 17 | 18 | ```shell 19 | $ python main.py -h 20 | usage: main.py [-h] [-V] [--log-level LOG_LEVEL] 21 | [postman_testset_file] [output_testset_file] 22 | 23 | Convert postman testcases to JSON testcases for HttpRunner. 24 | 25 | positional arguments: 26 | postman_testset_file Specify postman testset file. 27 | output_testset_file Optional. Specify converted JSON testset file. 28 | 29 | optional arguments: 30 | -h, --help show this help message and exit 31 | -V, --version show version 32 | --log-level LOG_LEVEL 33 | Specify logging level, default is INFO. 34 | ``` 35 | 36 | ## examples 37 | 38 | In most cases, you can run ``postman2case`` like this: 39 | 40 | ```shell 41 | $ python3 main.py test/test.json output.json 42 | INFO:root:Generate JSON testset successfully: output.json 43 | ``` 44 | 45 | As you see, the first parameter is postman source file path, and the second is converted JSON file path. 46 | 47 | The output testset file type is detemined by the suffix of your specified file. 48 | 49 | If you only specify postman source file path, the output testset is in JSON format by default and located in the same folder with source file. 50 | 51 | ```shell 52 | $ python3 main.py test/test.json 53 | INFO:root:Generate JSON testset successfully: test/test.output.json 54 | ``` 55 | 56 | ## generated testset 57 | 58 | generated JSON testset ``output.json`` shows like this: 59 | 60 | ```json 61 | [ 62 | { 63 | "test": { 64 | "name": "/api/v1/Account/Login", 65 | "request": { 66 | "method": "POST", 67 | "url": "https://httprunner.top/api/v1/Account/Login", 68 | "headers": { 69 | "Content-Type": "application/json" 70 | }, 71 | "json": { 72 | "UserName": "test001", 73 | "Pwd": "123", 74 | "VerCode": "" 75 | } 76 | }, 77 | "validate": [] 78 | } 79 | } 80 | ] 81 | ``` 82 | 83 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """ used for debugging 2 | """ 3 | 4 | from postman2case.cli import main 5 | main() 6 | -------------------------------------------------------------------------------- /postman2case/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.0.1' -------------------------------------------------------------------------------- /postman2case/cli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | import os 4 | import sys 5 | 6 | from postman2case import __version__ 7 | from postman2case.core import PostmanParser 8 | 9 | 10 | def main(): 11 | parser = argparse.ArgumentParser( 12 | description="Convert postman testcases to JSON testcases for HttpRunner.") 13 | parser.add_argument("-V", "--version", dest='version', action='store_true', 14 | help="show version") 15 | parser.add_argument('--log-level', default='INFO', 16 | help="Specify logging level, default is INFO.") 17 | 18 | parser.add_argument('postman_testset_file', nargs='?', 19 | help="Specify postman testset file.") 20 | 21 | parser.add_argument('--output_file_type', nargs='?', 22 | help="Optional. Specify output file type.") 23 | 24 | parser.add_argument('--output_dir', nargs='?', 25 | help="Optional. Specify output directory.") 26 | 27 | args = parser.parse_args() 28 | 29 | if args.version: 30 | print("{}".format(__version__)) 31 | exit(0) 32 | 33 | log_level = getattr(logging, args.log_level.upper()) 34 | logging.basicConfig(level=log_level) 35 | 36 | postman_testset_file = args.postman_testset_file 37 | output_file_type = args.output_file_type 38 | output_dir = args.output_dir 39 | 40 | if not postman_testset_file or not postman_testset_file.endswith(".json"): 41 | logging.error("postman_testset_file file not specified.") 42 | sys.exit(1) 43 | 44 | if not output_file_type: 45 | output_file_type = "json" 46 | else: 47 | output_file_type = output_file_type.lower() 48 | if output_file_type not in ["json", "yml", "yaml"]: 49 | logging.error("output file only support json/yml/yaml.") 50 | sys.exit(1) 51 | 52 | if not output_dir: 53 | output_dir = '.' 54 | 55 | postman_parser = PostmanParser(postman_testset_file) 56 | parse_result = postman_parser.parse_data() 57 | postman_parser.save(parse_result, output_dir, output_file_type=output_file_type) 58 | 59 | return 0 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /postman2case/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | httprunner.compat 5 | ~~~~~~~~~~~~~~~~~ 6 | 7 | This module handles import compatibility issues between Python 2 and 8 | Python 3. 9 | """ 10 | 11 | import sys 12 | 13 | # ------- 14 | # Pythons 15 | # ------- 16 | 17 | # Syntax sugar. 18 | _ver = sys.version_info 19 | 20 | #: Python 2.x? 21 | is_py2 = (_ver[0] == 2) 22 | 23 | #: Python 3.x? 24 | is_py3 = (_ver[0] == 3) 25 | 26 | try: 27 | import simplejson as json 28 | except ImportError: 29 | import json 30 | 31 | # --------- 32 | # Specifics 33 | # --------- 34 | 35 | if is_py2: 36 | 37 | ensure_ascii = True 38 | builtin_str = str 39 | bytes = str 40 | str = unicode 41 | basestring = basestring 42 | numeric_types = (int, long, float) 43 | integer_types = (int, long) 44 | 45 | elif is_py3: 46 | 47 | ensure_ascii = False 48 | builtin_str = str 49 | str = str 50 | bytes = bytes 51 | basestring = (str, bytes) 52 | numeric_types = (int, float) 53 | integer_types = (int,) 54 | -------------------------------------------------------------------------------- /postman2case/core.py: -------------------------------------------------------------------------------- 1 | import io 2 | import json 3 | import logging 4 | import os 5 | import yaml 6 | from collections import OrderedDict 7 | 8 | from postman2case.compat import ensure_ascii 9 | from postman2case.parser import parse_value_from_type 10 | 11 | 12 | class PostmanParser(object): 13 | def __init__(self, postman_testcase_file): 14 | self.postman_testcase_file = postman_testcase_file 15 | 16 | def read_postman_data(self): 17 | with open(self.postman_testcase_file, encoding='utf-8', mode='r') as file: 18 | postman_data = json.load(file) 19 | 20 | return postman_data 21 | 22 | def parse_url(self, request_url): 23 | url = "" 24 | if isinstance(request_url, str): 25 | url = request_url 26 | elif isinstance(request_url, dict): 27 | if "raw" in request_url.keys(): 28 | url= request_url["raw"] 29 | return url 30 | 31 | def parse_header(self, request_header): 32 | headers = {} 33 | for header in request_header: 34 | headers[header["key"]] = header["value"] 35 | return headers 36 | 37 | def parse_each_item(self, item): 38 | """ parse each item in postman to testcase in httprunner 39 | """ 40 | api = {} 41 | api["name"] = item["name"] 42 | api["validate"] = [] 43 | api["variables"] = [] 44 | 45 | request = {} 46 | request["method"] = item["request"]["method"] 47 | 48 | url = self.parse_url(item["request"]["url"]) 49 | 50 | if request["method"] == "GET": 51 | request["url"] = url.split("?")[0] 52 | request["headers"] = self.parse_header(item["request"]["header"]) 53 | 54 | body = {} 55 | if "query" in item["request"]["url"].keys(): 56 | for query in item["request"]["url"]["query"]: 57 | api["variables"].append({query["key"]: parse_value_from_type(query["value"])}) 58 | body[query["key"]] = "$"+query["key"] 59 | request["params"] = body 60 | else: 61 | request["url"] = url 62 | request["headers"] = self.parse_header(item["request"]["header"]) 63 | 64 | body = {} 65 | if item["request"]["body"] != {}: 66 | mode = item["request"]["body"]["mode"] 67 | if isinstance(item["request"]["body"][mode], list): 68 | for param in item["request"]["body"][mode]: 69 | if param["type"] == "text": 70 | api["variables"].append({param["key"]: parse_value_from_type(param["value"])}) 71 | else: 72 | api["variables"].append({param["key"]: parse_value_from_type(param["src"])}) 73 | body[param["key"]] = "$"+param["key"] 74 | elif isinstance(item["request"]["body"][mode], str): 75 | 76 | body = item["request"]["body"][mode] 77 | request["data"] = body 78 | 79 | api["request"] = request 80 | return api 81 | 82 | def parse_items(self, items, folder_name=None): 83 | result = [] 84 | for folder in items: 85 | if "item" in folder.keys(): 86 | name = folder["name"].replace(" ", "_") 87 | if folder_name: 88 | name = os.path.join(folder_name, name) 89 | temp = self.parse_items(folder["item"], name) 90 | result += temp 91 | else: 92 | api = self.parse_each_item(folder) 93 | api["folder_name"] = folder_name 94 | result.append(api) 95 | return result 96 | 97 | def parse_data(self): 98 | """ dump postman data to json testset 99 | """ 100 | logging.info("Start to generate JSON testset.") 101 | postman_data = self.read_postman_data() 102 | 103 | result = self.parse_items(postman_data["item"], None) 104 | return result 105 | 106 | def save(self, data, output_dir, output_file_type="json"): 107 | count = 0 108 | output_dir = os.path.join(output_dir, "api") 109 | if not os.path.exists(output_dir): 110 | os.makedirs(output_dir) 111 | for each_api in data: 112 | count += 1 113 | file_name = str(count) + "." + output_file_type 114 | 115 | folder_name = each_api.pop("folder_name") 116 | if folder_name: 117 | folder_path = os.path.join(output_dir, folder_name) 118 | if not os.path.exists(folder_path): 119 | os.makedirs(folder_path) 120 | file_path = os.path.join(folder_path, file_name) 121 | else: 122 | file_path = os.path.join(output_dir, file_name) 123 | if os.path.isfile(file_path): 124 | logging.error("{} file had exist.".format(file_path)) 125 | continue 126 | if output_file_type == "json": 127 | with io.open(file_path, 'w', encoding="utf-8") as outfile: 128 | my_json_str = json.dumps(each_api, ensure_ascii=ensure_ascii, indent=4) 129 | if isinstance(my_json_str, bytes): 130 | my_json_str = my_json_str.decode("utf-8") 131 | 132 | outfile.write(my_json_str) 133 | else: 134 | with io.open(file_path, 'w', encoding="utf-8") as outfile: 135 | my_json_str = json.dumps(each_api, ensure_ascii=ensure_ascii, indent=4) 136 | yaml.dump(each_api, outfile, allow_unicode=True, default_flow_style=False, indent=4) 137 | 138 | logging.info("Generate JSON testset successfully: {}".format(file_path)) 139 | -------------------------------------------------------------------------------- /postman2case/parser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def parse_value_from_type(value): 4 | if isinstance(value, int): 5 | return int(value) 6 | elif isinstance(value, float): 7 | return float(value) 8 | elif value.lower() == "false": 9 | return False 10 | elif value.lower() == "true": 11 | return True 12 | else: 13 | return str(value) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #encoding: utf-8 2 | import io 3 | 4 | from postman2case import __version__ 5 | from setuptools import find_packages, setup 6 | 7 | with io.open("README.md", encoding='utf-8') as f: 8 | long_description = f.read() 9 | 10 | setup( 11 | name='postman2case', 12 | version=__version__, 13 | description='Convert POSTMAN data to JSON testcases for HttpRunner.', 14 | long_description=long_description, 15 | author='luguo', 16 | author_email='hluguoj@163.com', 17 | url='https://github.com/HttpRunner/postman2case', 18 | license='MIT', 19 | packages=find_packages(exclude=['test.*', 'test']), 20 | package_data={}, 21 | keywords='postman converter json', 22 | install_requires=[], 23 | classifiers=[ 24 | "Development Status :: 3 - Alpha", 25 | 'Programming Language :: Python :: 2.7', 26 | 'Programming Language :: Python :: 3.4', 27 | 'Programming Language :: Python :: 3.5', 28 | 'Programming Language :: Python :: 3.6' 29 | ], 30 | entry_points={ 31 | 'console_scripts': [ 32 | 'postman2case=postman2case.cli:main' 33 | ] 34 | } 35 | ) 36 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/httprunner/postman2case/436c973f518aef40ab0b04cbd4cf4cb72104ad2a/tests/__init__.py -------------------------------------------------------------------------------- /tests/data/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "02c4cc76-4dc3-4e99-b1f0-1d777a3679e0", 4 | "name": "postman2case", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "Request Methods", 10 | "item": [ 11 | { 12 | "name": "GET Request", 13 | "event": [ 14 | { 15 | "listen": "test", 16 | "script": { 17 | "id": "edd1a6f5-abb9-4bd9-9f25-b5e6e0801117", 18 | "exec": [ 19 | "pm.test(\"response is ok\", function () {", 20 | " pm.response.to.have.status(200);", 21 | "});", 22 | "", 23 | "pm.test(\"response body has json with request queries\", function () {", 24 | " pm.response.to.have.jsonBody('args.foo1', 'bar1')", 25 | " .and.have.jsonBody('args.foo2', 'bar2');", 26 | "});" 27 | ], 28 | "type": "text/javascript" 29 | } 30 | } 31 | ], 32 | "request": { 33 | "method": "GET", 34 | "header": [], 35 | "body": { 36 | "mode": "raw", 37 | "raw": "" 38 | }, 39 | "url": { 40 | "raw": "https://postman-echo.com/get?foo1=bar1&foo2=bar2", 41 | "protocol": "https", 42 | "host": [ 43 | "postman-echo", 44 | "com" 45 | ], 46 | "path": [ 47 | "get" 48 | ], 49 | "query": [ 50 | { 51 | "key": "foo1", 52 | "value": "bar1" 53 | }, 54 | { 55 | "key": "foo2", 56 | "value": "bar2" 57 | } 58 | ] 59 | }, 60 | "description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested." 61 | }, 62 | "response": [] 63 | }, 64 | { 65 | "name": "POST Raw Text", 66 | "event": [ 67 | { 68 | "listen": "test", 69 | "script": { 70 | "type": "text/javascript", 71 | "exec": [ 72 | "pm.test(\"response is ok\", function () {", 73 | " pm.response.to.have.status(200);", 74 | "});", 75 | "", 76 | "pm.test(\"response body has json with request body\", function () {", 77 | " pm.response.to.have.jsonBody('data', ", 78 | " 'This is expected to be sent back as part of response body.');", 79 | "});" 80 | ] 81 | } 82 | } 83 | ], 84 | "request": { 85 | "method": "POST", 86 | "header": [], 87 | "body": { 88 | "mode": "raw", 89 | "raw": "This is expected to be sent back as part of response body." 90 | }, 91 | "url": { 92 | "raw": "https://postman-echo.com/post", 93 | "protocol": "https", 94 | "host": [ 95 | "postman-echo", 96 | "com" 97 | ], 98 | "path": [ 99 | "post" 100 | ] 101 | }, 102 | "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." 103 | }, 104 | "response": [] 105 | }, 106 | { 107 | "name": "POST Form Data", 108 | "event": [ 109 | { 110 | "listen": "test", 111 | "script": { 112 | "type": "text/javascript", 113 | "exec": [ 114 | "pm.test(\"response is ok\", function () {", 115 | " pm.response.to.have.status(200);", 116 | "});", 117 | "", 118 | "pm.test(\"response body has json with form data\", function () {", 119 | " pm.response.to.have.jsonBody('form.foo1', 'bar1')", 120 | " .and.have.jsonBody('form.foo2', 'bar2');", 121 | "});" 122 | ] 123 | } 124 | } 125 | ], 126 | "request": { 127 | "method": "POST", 128 | "header": [], 129 | "body": { 130 | "mode": "urlencoded", 131 | "urlencoded": [ 132 | { 133 | "key": "foo1", 134 | "value": "bar1", 135 | "type": "text" 136 | }, 137 | { 138 | "key": "foo2", 139 | "value": "bar2", 140 | "type": "text" 141 | } 142 | ] 143 | }, 144 | "url": { 145 | "raw": "https://postman-echo.com/post", 146 | "protocol": "https", 147 | "host": [ 148 | "postman-echo", 149 | "com" 150 | ], 151 | "path": [ 152 | "post" 153 | ] 154 | }, 155 | "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested when data is sent as a form parameter." 156 | }, 157 | "response": [] 158 | }, 159 | { 160 | "name": "PUT Request", 161 | "event": [ 162 | { 163 | "listen": "test", 164 | "script": { 165 | "type": "text/javascript", 166 | "exec": [ 167 | "pm.test(\"response is ok\", function () {", 168 | " pm.response.to.have.status(200);", 169 | "});", 170 | "", 171 | "pm.test(\"response body has json with form data\", function () {", 172 | " pm.response.to.have.jsonBody('data', ", 173 | " 'This is expected to be sent back as part of response body.');", 174 | "});" 175 | ] 176 | } 177 | } 178 | ], 179 | "request": { 180 | "method": "PUT", 181 | "header": [], 182 | "body": { 183 | "mode": "raw", 184 | "raw": "This is expected to be sent back as part of response body." 185 | }, 186 | "url": { 187 | "raw": "https://postman-echo.com/put", 188 | "protocol": "https", 189 | "host": [ 190 | "postman-echo", 191 | "com" 192 | ], 193 | "path": [ 194 | "put" 195 | ] 196 | }, 197 | "description": "The HTTP `PUT` request method is similar to HTTP `POST`. It too is meant to \ntransfer data to a server (and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `PUT` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following \nraw HTTP request,\n\n> PUT /hi/there?hand=wave\n>\n> \n\n\n" 198 | }, 199 | "response": [] 200 | }, 201 | { 202 | "name": "PATCH Request", 203 | "event": [ 204 | { 205 | "listen": "test", 206 | "script": { 207 | "type": "text/javascript", 208 | "exec": [ 209 | "pm.test(\"response is ok\", function () {", 210 | " pm.response.to.have.status(200);", 211 | "});", 212 | "", 213 | "pm.test(\"response body has json with form data\", function () {", 214 | " pm.response.to.have.jsonBody('data', ", 215 | " 'This is expected to be sent back as part of response body.');", 216 | "});" 217 | ] 218 | } 219 | } 220 | ], 221 | "request": { 222 | "method": "PATCH", 223 | "header": [], 224 | "body": { 225 | "mode": "raw", 226 | "raw": "This is expected to be sent back as part of response body." 227 | }, 228 | "url": { 229 | "raw": "https://postman-echo.com/patch", 230 | "protocol": "https", 231 | "host": [ 232 | "postman-echo", 233 | "com" 234 | ], 235 | "path": [ 236 | "patch" 237 | ] 238 | }, 239 | "description": "The HTTP `PATCH` method is used to update resources on a server. The exact\nuse of `PATCH` requests depends on the server in question. There are a number\nof server implementations which handle `PATCH` differently. Technically, \n`PATCH` supports both Query String parameters and a Request Body.\n\nThis endpoint accepts an HTTP `PATCH` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." 240 | }, 241 | "response": [] 242 | }, 243 | { 244 | "name": "DELETE Request", 245 | "event": [ 246 | { 247 | "listen": "test", 248 | "script": { 249 | "type": "text/javascript", 250 | "exec": [ 251 | "pm.test(\"response is ok\", function () {", 252 | " pm.response.to.have.status(200);", 253 | "});", 254 | "", 255 | "pm.test(\"response body has json with form data\", function () {", 256 | " pm.response.to.have.jsonBody('data', ", 257 | " 'This is expected to be sent back as part of response body.');", 258 | "});" 259 | ] 260 | } 261 | } 262 | ], 263 | "request": { 264 | "method": "DELETE", 265 | "header": [], 266 | "body": { 267 | "mode": "raw", 268 | "raw": "This is expected to be sent back as part of response body." 269 | }, 270 | "url": { 271 | "raw": "https://postman-echo.com/delete", 272 | "protocol": "https", 273 | "host": [ 274 | "postman-echo", 275 | "com" 276 | ], 277 | "path": [ 278 | "delete" 279 | ] 280 | }, 281 | "description": "The HTTP `DELETE` method is used to delete resources on a server. The exact\nuse of `DELETE` requests depends on the server implementation. In general, \n`DELETE` requests support both, Query String parameters as well as a Request \nBody.\n\nThis endpoint accepts an HTTP `DELETE` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." 282 | }, 283 | "response": [] 284 | }, 285 | { 286 | "name": "post_json", 287 | "request": { 288 | "method": "POST", 289 | "header": [ 290 | { 291 | "key": "Content-Type", 292 | "name": "Content-Type", 293 | "type": "text", 294 | "value": "application/json" 295 | } 296 | ], 297 | "body": { 298 | "mode": "raw", 299 | "raw": "{\n \"foo1\": \"bar1\",\n \"foo2\": 2\n}" 300 | }, 301 | "url": { 302 | "raw": "https://postman-echo.com/post", 303 | "protocol": "https", 304 | "host": [ 305 | "postman-echo", 306 | "com" 307 | ], 308 | "path": [ 309 | "post" 310 | ] 311 | } 312 | }, 313 | "response": [] 314 | }, 315 | { 316 | "name": "post_none", 317 | "request": { 318 | "method": "POST", 319 | "header": [], 320 | "body": { 321 | "mode": "raw", 322 | "raw": "" 323 | }, 324 | "url": { 325 | "raw": "https://postman-echo.com/post", 326 | "protocol": "https", 327 | "host": [ 328 | "postman-echo", 329 | "com" 330 | ], 331 | "path": [ 332 | "post" 333 | ] 334 | } 335 | }, 336 | "response": [] 337 | }, 338 | { 339 | "name": "post_form", 340 | "request": { 341 | "method": "POST", 342 | "header": [], 343 | "body": { 344 | "mode": "formdata", 345 | "formdata": [ 346 | { 347 | "key": "foo1", 348 | "value": "false", 349 | "type": "text" 350 | }, 351 | { 352 | "key": "foo2", 353 | "value": "jjjj", 354 | "type": "text" 355 | }, 356 | { 357 | "key": "foo3", 358 | "value": "4", 359 | "type": "text" 360 | } 361 | ] 362 | }, 363 | "url": { 364 | "raw": "https://postman-echo.com/post", 365 | "protocol": "https", 366 | "host": [ 367 | "postman-echo", 368 | "com" 369 | ], 370 | "path": [ 371 | "post" 372 | ] 373 | } 374 | }, 375 | "response": [] 376 | }, 377 | { 378 | "name": "post_file", 379 | "request": { 380 | "method": "POST", 381 | "header": [], 382 | "body": { 383 | "mode": "formdata", 384 | "formdata": [ 385 | { 386 | "key": "foo1", 387 | "type": "file", 388 | "src": "" 389 | }, 390 | { 391 | "key": "foo2", 392 | "value": "d", 393 | "type": "text" 394 | } 395 | ] 396 | }, 397 | "url": { 398 | "raw": "https://postman-echo.com/post", 399 | "protocol": "https", 400 | "host": [ 401 | "postman-echo", 402 | "com" 403 | ], 404 | "path": [ 405 | "post" 406 | ] 407 | } 408 | }, 409 | "response": [] 410 | } 411 | ], 412 | "description": "HTTP has multiple request \"verbs\", such as `GET`, `PUT`, `POST`, `DELETE`,\n`PATCH`, `HEAD`, etc. \n\nAn HTTP Method (verb) defines how a request should be interpreted by a server. \nThe endpoints in this section demonstrate various HTTP Verbs. Postman supports \nall the HTTP Verbs, including some rarely used ones, such as `PROPFIND`, `UNLINK`, \netc.\n\nFor details about HTTP Verbs, refer to [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9)\n" 413 | }, 414 | { 415 | "name": "aaa", 416 | "item": [ 417 | { 418 | "name": "Request Methods Copy", 419 | "item": [ 420 | { 421 | "name": "GET Request", 422 | "event": [ 423 | { 424 | "listen": "test", 425 | "script": { 426 | "id": "edd1a6f5-abb9-4bd9-9f25-b5e6e0801117", 427 | "exec": [ 428 | "pm.test(\"response is ok\", function () {", 429 | " pm.response.to.have.status(200);", 430 | "});", 431 | "", 432 | "pm.test(\"response body has json with request queries\", function () {", 433 | " pm.response.to.have.jsonBody('args.foo1', 'bar1')", 434 | " .and.have.jsonBody('args.foo2', 'bar2');", 435 | "});" 436 | ], 437 | "type": "text/javascript" 438 | } 439 | } 440 | ], 441 | "request": { 442 | "method": "GET", 443 | "header": [], 444 | "body": { 445 | "mode": "raw", 446 | "raw": "" 447 | }, 448 | "url": { 449 | "raw": "https://postman-echo.com/get?foo1=bar1&foo2=bar2", 450 | "protocol": "https", 451 | "host": [ 452 | "postman-echo", 453 | "com" 454 | ], 455 | "path": [ 456 | "get" 457 | ], 458 | "query": [ 459 | { 460 | "key": "foo1", 461 | "value": "bar1" 462 | }, 463 | { 464 | "key": "foo2", 465 | "value": "bar2" 466 | } 467 | ] 468 | }, 469 | "description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested." 470 | }, 471 | "response": [] 472 | }, 473 | { 474 | "name": "POST Raw Text", 475 | "event": [ 476 | { 477 | "listen": "test", 478 | "script": { 479 | "type": "text/javascript", 480 | "exec": [ 481 | "pm.test(\"response is ok\", function () {", 482 | " pm.response.to.have.status(200);", 483 | "});", 484 | "", 485 | "pm.test(\"response body has json with request body\", function () {", 486 | " pm.response.to.have.jsonBody('data', ", 487 | " 'This is expected to be sent back as part of response body.');", 488 | "});" 489 | ] 490 | } 491 | } 492 | ], 493 | "request": { 494 | "method": "POST", 495 | "header": [], 496 | "body": { 497 | "mode": "raw", 498 | "raw": "This is expected to be sent back as part of response body." 499 | }, 500 | "url": { 501 | "raw": "https://postman-echo.com/post", 502 | "protocol": "https", 503 | "host": [ 504 | "postman-echo", 505 | "com" 506 | ], 507 | "path": [ 508 | "post" 509 | ] 510 | }, 511 | "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested." 512 | }, 513 | "response": [] 514 | }, 515 | { 516 | "name": "POST Form Data", 517 | "event": [ 518 | { 519 | "listen": "test", 520 | "script": { 521 | "type": "text/javascript", 522 | "exec": [ 523 | "pm.test(\"response is ok\", function () {", 524 | " pm.response.to.have.status(200);", 525 | "});", 526 | "", 527 | "pm.test(\"response body has json with form data\", function () {", 528 | " pm.response.to.have.jsonBody('form.foo1', 'bar1')", 529 | " .and.have.jsonBody('form.foo2', 'bar2');", 530 | "});" 531 | ] 532 | } 533 | } 534 | ], 535 | "request": { 536 | "method": "POST", 537 | "header": [], 538 | "body": { 539 | "mode": "urlencoded", 540 | "urlencoded": [ 541 | { 542 | "key": "foo1", 543 | "value": "bar1", 544 | "type": "text" 545 | }, 546 | { 547 | "key": "foo2", 548 | "value": "bar2", 549 | "type": "text" 550 | } 551 | ] 552 | }, 553 | "url": { 554 | "raw": "https://postman-echo.com/post", 555 | "protocol": "https", 556 | "host": [ 557 | "postman-echo", 558 | "com" 559 | ], 560 | "path": [ 561 | "post" 562 | ] 563 | }, 564 | "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested when data is sent as a form parameter." 565 | }, 566 | "response": [] 567 | }, 568 | { 569 | "name": "PUT Request", 570 | "event": [ 571 | { 572 | "listen": "test", 573 | "script": { 574 | "type": "text/javascript", 575 | "exec": [ 576 | "pm.test(\"response is ok\", function () {", 577 | " pm.response.to.have.status(200);", 578 | "});", 579 | "", 580 | "pm.test(\"response body has json with form data\", function () {", 581 | " pm.response.to.have.jsonBody('data', ", 582 | " 'This is expected to be sent back as part of response body.');", 583 | "});" 584 | ] 585 | } 586 | } 587 | ], 588 | "request": { 589 | "method": "PUT", 590 | "header": [], 591 | "body": { 592 | "mode": "raw", 593 | "raw": "This is expected to be sent back as part of response body." 594 | }, 595 | "url": { 596 | "raw": "https://postman-echo.com/put", 597 | "protocol": "https", 598 | "host": [ 599 | "postman-echo", 600 | "com" 601 | ], 602 | "path": [ 603 | "put" 604 | ] 605 | }, 606 | "description": "The HTTP `PUT` request method is similar to HTTP `POST`. It too is meant to \ntransfer data to a server (and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `PUT` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following \nraw HTTP request,\n\n> PUT /hi/there?hand=wave\n>\n> \n\n\n" 607 | }, 608 | "response": [] 609 | }, 610 | { 611 | "name": "PATCH Request", 612 | "event": [ 613 | { 614 | "listen": "test", 615 | "script": { 616 | "type": "text/javascript", 617 | "exec": [ 618 | "pm.test(\"response is ok\", function () {", 619 | " pm.response.to.have.status(200);", 620 | "});", 621 | "", 622 | "pm.test(\"response body has json with form data\", function () {", 623 | " pm.response.to.have.jsonBody('data', ", 624 | " 'This is expected to be sent back as part of response body.');", 625 | "});" 626 | ] 627 | } 628 | } 629 | ], 630 | "request": { 631 | "method": "PATCH", 632 | "header": [], 633 | "body": { 634 | "mode": "raw", 635 | "raw": "This is expected to be sent back as part of response body." 636 | }, 637 | "url": { 638 | "raw": "https://postman-echo.com/patch", 639 | "protocol": "https", 640 | "host": [ 641 | "postman-echo", 642 | "com" 643 | ], 644 | "path": [ 645 | "patch" 646 | ] 647 | }, 648 | "description": "The HTTP `PATCH` method is used to update resources on a server. The exact\nuse of `PATCH` requests depends on the server in question. There are a number\nof server implementations which handle `PATCH` differently. Technically, \n`PATCH` supports both Query String parameters and a Request Body.\n\nThis endpoint accepts an HTTP `PATCH` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." 649 | }, 650 | "response": [] 651 | }, 652 | { 653 | "name": "DELETE Request", 654 | "event": [ 655 | { 656 | "listen": "test", 657 | "script": { 658 | "type": "text/javascript", 659 | "exec": [ 660 | "pm.test(\"response is ok\", function () {", 661 | " pm.response.to.have.status(200);", 662 | "});", 663 | "", 664 | "pm.test(\"response body has json with form data\", function () {", 665 | " pm.response.to.have.jsonBody('data', ", 666 | " 'This is expected to be sent back as part of response body.');", 667 | "});" 668 | ] 669 | } 670 | } 671 | ], 672 | "request": { 673 | "method": "DELETE", 674 | "header": [], 675 | "body": { 676 | "mode": "raw", 677 | "raw": "This is expected to be sent back as part of response body." 678 | }, 679 | "url": { 680 | "raw": "https://postman-echo.com/delete", 681 | "protocol": "https", 682 | "host": [ 683 | "postman-echo", 684 | "com" 685 | ], 686 | "path": [ 687 | "delete" 688 | ] 689 | }, 690 | "description": "The HTTP `DELETE` method is used to delete resources on a server. The exact\nuse of `DELETE` requests depends on the server implementation. In general, \n`DELETE` requests support both, Query String parameters as well as a Request \nBody.\n\nThis endpoint accepts an HTTP `DELETE` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body." 691 | }, 692 | "response": [] 693 | }, 694 | { 695 | "name": "post_json", 696 | "request": { 697 | "method": "POST", 698 | "header": [ 699 | { 700 | "key": "Content-Type", 701 | "name": "Content-Type", 702 | "value": "application/json", 703 | "type": "text" 704 | } 705 | ], 706 | "body": { 707 | "mode": "raw", 708 | "raw": "{\n\t\"foo1\": \"bar1\",\n\t\"foo2\": 2\n}" 709 | }, 710 | "url": { 711 | "raw": "https://postman-echo.com/post", 712 | "protocol": "https", 713 | "host": [ 714 | "postman-echo", 715 | "com" 716 | ], 717 | "path": [ 718 | "post" 719 | ] 720 | } 721 | }, 722 | "response": [] 723 | }, 724 | { 725 | "name": "post_none", 726 | "request": { 727 | "method": "POST", 728 | "header": [], 729 | "body": { 730 | "mode": "raw", 731 | "raw": "" 732 | }, 733 | "url": { 734 | "raw": "https://postman-echo.com/post", 735 | "protocol": "https", 736 | "host": [ 737 | "postman-echo", 738 | "com" 739 | ], 740 | "path": [ 741 | "post" 742 | ] 743 | } 744 | }, 745 | "response": [] 746 | }, 747 | { 748 | "name": "post_form", 749 | "request": { 750 | "method": "POST", 751 | "header": [], 752 | "body": { 753 | "mode": "formdata", 754 | "formdata": [ 755 | { 756 | "key": "foo1", 757 | "value": "false", 758 | "type": "text" 759 | }, 760 | { 761 | "key": "foo2", 762 | "value": "jjjj", 763 | "type": "text" 764 | }, 765 | { 766 | "key": "foo3", 767 | "value": "4", 768 | "type": "text" 769 | } 770 | ] 771 | }, 772 | "url": { 773 | "raw": "https://postman-echo.com/post", 774 | "protocol": "https", 775 | "host": [ 776 | "postman-echo", 777 | "com" 778 | ], 779 | "path": [ 780 | "post" 781 | ] 782 | } 783 | }, 784 | "response": [] 785 | }, 786 | { 787 | "name": "post_file", 788 | "request": { 789 | "method": "POST", 790 | "header": [], 791 | "body": { 792 | "mode": "formdata", 793 | "formdata": [ 794 | { 795 | "key": "foo1", 796 | "type": "file", 797 | "src": "" 798 | }, 799 | { 800 | "key": "foo2", 801 | "value": "d", 802 | "type": "text" 803 | } 804 | ] 805 | }, 806 | "url": { 807 | "raw": "https://postman-echo.com/post", 808 | "protocol": "https", 809 | "host": [ 810 | "postman-echo", 811 | "com" 812 | ], 813 | "path": [ 814 | "post" 815 | ] 816 | } 817 | }, 818 | "response": [] 819 | } 820 | ], 821 | "description": "HTTP has multiple request \"verbs\", such as `GET`, `PUT`, `POST`, `DELETE`,\n`PATCH`, `HEAD`, etc. \n\nAn HTTP Method (verb) defines how a request should be interpreted by a server. \nThe endpoints in this section demonstrate various HTTP Verbs. Postman supports \nall the HTTP Verbs, including some rarely used ones, such as `PROPFIND`, `UNLINK`, \netc.\n\nFor details about HTTP Verbs, refer to [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9)\n", 822 | "_postman_isSubFolder": true 823 | } 824 | ] 825 | }, 826 | { 827 | "name": "test", 828 | "request": { 829 | "method": "GET", 830 | "header": [], 831 | "body": { 832 | "mode": "raw", 833 | "raw": "" 834 | }, 835 | "url": { 836 | "raw": "https://www.baidu.com", 837 | "protocol": "https", 838 | "host": [ 839 | "www", 840 | "baidu", 841 | "com" 842 | ] 843 | } 844 | }, 845 | "response": [] 846 | } 847 | ] 848 | } -------------------------------------------------------------------------------- /tests/data/test_get.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test_get", 3 | "request": { 4 | "url": { 5 | "raw": "http://www.baidu.com?search=345", 6 | "protocol": "http", 7 | "host": [ 8 | "www", 9 | "baidu", 10 | "com" 11 | ], 12 | "query": [ 13 | { 14 | "key": "search", 15 | "value": "345", 16 | "equals": true, 17 | "description": "" 18 | } 19 | ], 20 | "variable": [] 21 | }, 22 | "method": "GET", 23 | "header": [], 24 | "body": {}, 25 | "description": "" 26 | }, 27 | "response": [] 28 | } -------------------------------------------------------------------------------- /tests/data/test_post.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test_post", 3 | "request": { 4 | "url": "http://www.baidu.com", 5 | "method": "POST", 6 | "header": [], 7 | "body": { 8 | "mode": "formdata", 9 | "formdata": [ 10 | { 11 | "key": "search", 12 | "value": "123", 13 | "description": "", 14 | "type": "text" 15 | } 16 | ] 17 | }, 18 | "description": "" 19 | }, 20 | "response": [] 21 | } -------------------------------------------------------------------------------- /tests/test_postmanparser.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import json 4 | import shutil 5 | from postman2case.core import PostmanParser 6 | 7 | 8 | class TestParser(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.postman_parser = PostmanParser("tests/data/test.json") 12 | 13 | def test_init(self): 14 | self.assertEqual(self.postman_parser.postman_testcase_file, "tests/data/test.json") 15 | 16 | def test_read_postman_data(self): 17 | with open("tests/data/test.json", encoding='utf-8', mode='r') as f: 18 | content = json.load(f) 19 | other_content = self.postman_parser.read_postman_data() 20 | self.assertEqual(content, other_content) 21 | 22 | def test_parse_url(self): 23 | request_url = { 24 | "raw": "https://postman-echo.com/get?foo1=bar1&foo2=bar2", 25 | "protocol": "https", 26 | "host": [ 27 | "postman-echo", 28 | "com" 29 | ], 30 | "path": [ 31 | "get" 32 | ], 33 | "query": [ 34 | { 35 | "key": "foo1", 36 | "value": "bar1" 37 | }, 38 | { 39 | "key": "foo2", 40 | "value": "bar2" 41 | } 42 | ] 43 | } 44 | url = self.postman_parser.parse_url(request_url) 45 | self.assertEqual(url, request_url["raw"]) 46 | 47 | request_url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2" 48 | url = self.postman_parser.parse_url(request_url) 49 | self.assertEqual(url, request_url) 50 | 51 | def test_parse_header(self): 52 | request_header = [ 53 | { 54 | "key": "Content-Type", 55 | "name": "Content-Type", 56 | "value": "application/json", 57 | "type": "text" 58 | } 59 | ] 60 | target_header = { 61 | "Content-Type": "application/json" 62 | } 63 | header = self.postman_parser.parse_header(request_header) 64 | self.assertEqual(header, target_header) 65 | 66 | header = self.postman_parser.parse_header([]) 67 | self.assertEqual(header, {}) 68 | 69 | def test_parse_each_item_get(self): 70 | with open("tests/data/test_get.json", encoding='utf-8', mode='r') as f: 71 | item = json.load(f) 72 | 73 | result = { 74 | "name": "test_get", 75 | "validate": [], 76 | "variables": [ 77 | { 78 | "search": "345" 79 | } 80 | ], 81 | "request": { 82 | "method": "GET", 83 | "url": "http://www.baidu.com", 84 | "headers": {}, 85 | "params": { 86 | "search": "$search" 87 | } 88 | } 89 | } 90 | 91 | fun_result = self.postman_parser.parse_each_item(item) 92 | self.assertEqual(result, fun_result) 93 | 94 | def test_parse_each_item_post(self): 95 | with open("tests/data/test_post.json", encoding='utf-8', mode='r') as f: 96 | item = json.load(f) 97 | 98 | result = { 99 | "name": "test_post", 100 | "validate": [], 101 | "variables": [ 102 | { 103 | "search": "123" 104 | } 105 | ], 106 | "request": { 107 | "method": "POST", 108 | "url": "http://www.baidu.com", 109 | "headers": {}, 110 | "data": { 111 | "search": "$search" 112 | } 113 | } 114 | } 115 | fun_result = self.postman_parser.parse_each_item(item) 116 | self.assertEqual(result, fun_result) 117 | 118 | def test_parse_data(self): 119 | result = self.postman_parser.parse_data() 120 | self.assertEqual(len(result), 21) 121 | 122 | def test_save(self): 123 | result = self.postman_parser.parse_data() 124 | self.postman_parser.save(result, "save") 125 | shutil.rmtree("save") 126 | --------------------------------------------------------------------------------