Skip to main content

Convert Postman Collection v2.1 JSON files into executable pytest test suites

Project description

postman2pytest

CI codecov PyPI Downloads Python License: MIT

Convert a Postman Collection v2.1 JSON file into a ready-to-run pytest test suite. One command.

📖 Read the article on Dev.to

postman2pytest --collection my_api.json --out tests/test_api.py
BASE_URL=https://api.example.com pytest tests/test_api.py -v

Why

Postman collections document your API. postman2pytest turns that documentation into executable regression tests that run in CI. No manual rewriting, no drift.

Install

pip install postman2pytest

Or from source:

git clone https://github.com/golikovichev/postman2pytest
cd postman2pytest
pip install -e .

Usage

postman2pytest \
  --collection data/my_api.postman_collection.json \
  --out generated_tests/test_api.py

Then run the generated tests:

BASE_URL=https://staging.example.com pytest generated_tests/test_api.py -v

Options

Flag Required Description
--collection Path to Postman Collection v2.1 JSON
--out Output path for generated pytest file
--base-url Tip printed after generation (does not override env var)
--filter-folder Generate tests only for the named Postman folder

To regenerate tests for one folder, pass its Postman folder name:

postman2pytest \
  --collection data/my_api.postman_collection.json \
  --out generated_tests/test_users.py \
  --filter-folder Users

Examples

Generate tests for a single folder

The bundled data/sample_collection.json file includes a Users folder and one top-level Health check request. Generating from the whole collection creates three tests:

postman2pytest \
  --collection data/sample_collection.json \
  --out /tmp/test_all.py
Generated 3 test(s) -> /tmp/test_all.py

The generated file contains tests with folder-prefixed names:

def test_users_get_get_all_users():
def test_users_post_create_user():
def test_get_health_check():

To generate only the requests from the Users folder, pass --filter-folder. Folder matching is case-insensitive, so Users, users, and USERS all match the same folder:

postman2pytest \
  --collection data/sample_collection.json \
  --out /tmp/test_users.py \
  --filter-folder Users
Generated 2 test(s) -> /tmp/test_users.py

The filtered output contains only the tests from that folder:

def test_users_get_get_all_users():
def test_users_post_create_user():

How It Works

  1. Parse: reads the Postman Collection JSON, flattens nested folders into a flat request list
  2. Extract: captures method, URL, headers, body, and expected status from pm.response.to.have.status() test scripts
  3. Generate: renders a Jinja2 template into a .py file with one def test_*() per request

Variable substitution

Postman variables {{base_url}} become ENV_base_url in the URL, resolved at runtime via the BASE_URL environment variable.

Generated output example

Given a Postman request GET {{base_url}}/api/v1/users with a test asserting status 200, the output is:

def test_get_users():
    """GET ENV_base_url/api/v1/users"""
    url = f"{BASE_URL}/api/v1/users"
    headers = {}
    response = requests.get(url, headers=headers)
    assert response.status_code == 200, (
        f"Expected 200, got {response.status_code}: {response.text[:200]}"
    )

Supported features

  • ✅ Postman Collection v2.1 (v2.0 accepted with a warning)
  • ✅ Nested folders → flattened with folder prefix in test name
  • ✅ GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
  • ✅ Request headers (disabled headers excluded)
  • ✅ Raw JSON body
  • ✅ Expected status from pm.response.to.have.status(N) test scripts
  • ✅ Falls back to 200 when no status assertion found
  • ✅ Malformed items skipped with a warning. Rest of collection still generated

Limitations

Honest scope so you know what to expect before pointing the tool at a real collection.

  • Postman environments are not read. {{baseUrl}} and friends are passed through verbatim into the generated url strings. Set the BASE_URL env var at test time, or post-process the file to swap in the values you care about.
  • Pre-request scripts are skipped. Auth that depends on pm.sendRequest to grab a token before each call (e.g. OAuth client-credentials flows refreshing per request) needs manual translation into a pytest fixture.
  • Test scripts beyond a status assertion are dropped. Only pm.response.to.have.status(N) is extracted; chai-style body shape checks, custom JS, and pm.variables.set(...) calls do not survive the conversion.
  • Form-data and urlencoded bodies are not generated yet. Only raw JSON bodies are written into the test file. Multipart uploads, file attachments, and form fields are recognised by the parser but left out of the rendered request call. Tracked in issue #1.
  • Cookies, certificates, and per-request proxy settings are ignored.
  • Variable substitution is shallow. Path variables (/users/:id) become {id} placeholders; collection-level variables are not resolved.
  • Generated BASE_URL defaults to an empty string. Tests that hit a full URL in the Postman item still resolve, but bare path items will fail until the env var is set.

If a missing feature is blocking you, please open an issue with a redacted slice of the collection that demonstrates it.

Roadmap

Short list of what is next, roughly in priority order. Tracked in detail on the issues board.

  • Form-data and urlencoded body support: currently parsed but not rendered. Blocking most file-upload and OAuth-token-endpoint test cases. (#1)
  • Pre-request script translation, scoped scope: surface the script, even as a pytest.fixture stub, so the operator does not lose the auth context silently.
  • --ai-edges mode: opt-in pass that asks an LLM to fill in edge cases (boundary numbers, missing required fields, type-confusion payloads) on top of the deterministic happy-path tests. (#2)
  • Environment file ingestion: accept Postman environment JSON exports and write a matching conftest.py so {{baseUrl}} and similar resolve through pytest variables.
  • Allure step annotations toggle: --allure flag that wraps each generated test in allure.step(...) blocks so the report shows the Postman folder structure.

Contributions to any of the above are welcome. See CONTRIBUTING.md for the workflow.

Running tests

pip install pytest
pytest tests/ -v

Related projects and patterns

Once postman2pytest has generated your suite, the next questions are usually «how do I structure fixtures across all these requests» and «how do I run them under async with shared auth state». The tessl-labs/pytest-api-testing skill on the Tessl Registry collects the conventions that worked for that follow-on layer: httpx AsyncClient setup, conftest.py fixture shape, database isolation, parametrize patterns for edge cases, and auth-flow handling. Useful reference if your generated tests grow beyond the request-by-request shape this tool emits.

Sister projects in the same workspace:

  • secure-log2test: same idea but the input is Kibana / Elasticsearch JSON logs instead of Postman collections.
  • pytest-conversational: pytest plugin for multi-turn dialogue testing.

Contributing

See CONTRIBUTING.md.

Changelog

See CHANGELOG.md for release notes.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

postman2pytest-1.1.0.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

postman2pytest-1.1.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file postman2pytest-1.1.0.tar.gz.

File metadata

  • Download URL: postman2pytest-1.1.0.tar.gz
  • Upload date:
  • Size: 26.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for postman2pytest-1.1.0.tar.gz
Algorithm Hash digest
SHA256 0f5ca57a99a51b3d14d17781504248463c67fb7b93f59e8abefe5f1fdb7680de
MD5 ecaeaeaa01915006c7cfa20141ea8c15
BLAKE2b-256 cdb14f5a0509ba814bd902a9d158ec62eb20c0684626d008facf0a02d7c687d1

See more details on using hashes here.

File details

Details for the file postman2pytest-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: postman2pytest-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for postman2pytest-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bd8bac102c996fd7cf166fbab614e4eb8737d1dd64638da1666f91d02b8136af
MD5 20e40b65033f667efce83a72bbd1cc9b
BLAKE2b-256 5a0236fafabae538d0ad639e2f9813ba77ca518bbfab96bc92eb4b51ec9bafba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page