Convert a Postman Collection v2.1 JSON file into a runnable pytest test suite using the postman2pytest CLI. Use when the user has a Postman collection (a .postman_collection.json or v2.1 JSON export) and wants to run it as pytest in CI, when migrating from Postman/Newman to a Python-native test stack, when bridging Postman-documented APIs into a pytest-based regression suite, when the user asks to generate pytest tests from Postman, or when the user mentions wanting to keep Postman as the source of truth but run the suite with pytest.
93
100%
Does it follow best practices?
Impact
100%
1.00xAverage score across 2 eval scenarios
Passed
No known issues
Convert a Postman Collection v2.1 JSON file into a ready-to-run pytest test suite. One command.

postman2pytest --collection my_api.json --out tests/test_api.py
BASE_URL=https://api.example.com pytest tests/test_api.py -vPostman collections document your API. postman2pytest turns that documentation into executable regression tests that run in CI. No manual rewriting, no drift.
pip install postman2pytestOr from source:
git clone https://github.com/golikovichev/postman2pytest
cd postman2pytest
pip install -e .postman2pytest \
--collection data/my_api.postman_collection.json \
--out generated_tests/test_api.pyThen run the generated tests:
BASE_URL=https://staging.example.com pytest generated_tests/test_api.py -v| 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 UsersThe 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.pyGenerated 3 test(s) -> /tmp/test_all.pyThe 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 UsersGenerated 2 test(s) -> /tmp/test_users.pyThe filtered output contains only the tests from that folder:
def test_users_get_get_all_users():
def test_users_post_create_user():pm.response.to.have.status() test scripts.py file with one def test_*() per requestPostman variables {{base_url}} become ENV_base_url in the URL, resolved at runtime via the BASE_URL environment variable.
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]}"
)pm.response.to.have.status(N) test scriptsHonest scope so you know what to expect before pointing the tool at a real collection.
{{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.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.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.urlencoded and formdata bodies are now rendered as a data={...}
argument on the request. File-type form fields (uploads) are still skipped.
Tracked in
issue #1.data= (urlencoded). Repeated form keys collapse
to the last value, and a hand-set multipart/form-data Content-Type header
will not match the urlencoded body. Adjust by hand if your endpoint needs
multipart or multi-value keys./users/:id)
become {id} placeholders; collection-level variables are not resolved.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.
Short list of what is next, roughly in priority order. Tracked in detail on the issues board.
urlencoded and formdata text fields
now render as data={...} (OAuth-token-endpoint cases work). File-type
upload fields are still skipped.
(#1)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)conftest.py so {{baseUrl}} and similar resolve
through pytest variables.--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.
pip install pytest
pytest tests/ -vOnce 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:
See CONTRIBUTING.md.
See CHANGELOG.md for release notes.
MIT. See LICENSE.
.tessl-plugin
evals
scenario-1
scenario-2