microsoft/writing-python-sdk-spector-mock-api-tests
Writes TypeSpec http-client-python generator mock API tests (azure/unbranded/shared) from a Spector case. Use when given a Spector case link or a PR link that modifies Spector cases under http-specs/azure-http-specs.
npx skills add https://github.com/microsoft/typespec --skill writing-python-sdk-spector-mock-api-tests
You may receive either:
https://github.com/microsoft/typespec/tree/main/packages/http-specs/specs/...https://github.com/Azure/typespec-azure/tree/main/packages/azure-http-specs/specs/...Spector cases define the expected request + response. The goal is to add/extend python tests that validate the generated SDK behaves accordingly.
A python pytest test (sync) added to one of:
packages/http-client-python/tests/mock_api/azurepackages/http-client-python/tests/mock_api/unbrandedpackages/http-client-python/tests/mock_api/sharedAnd a corresponding async pytest test added under the matching asynctests/ folder:
packages/http-client-python/tests/mock_api/azure/asynctestspackages/http-client-python/tests/mock_api/unbranded/asynctestspackages/http-client-python/tests/mock_api/shared/asynctestsTest-writing progress:
python -m black <paths> --config ./eng/scripts/ci/config/pyproject.toml).chronus/changesBefore starting, ensure the build environment is ready:
pnpm install
tsp compile): cd packages/http-client-python
npm install
npm run build
> ⚠️ Do NOT run pnpm build at the repo root — it builds the entire monorepo (including the website) and takes 7+ minutes. Only the http-client-python package build is needed.
Use it directly.
packages/http-specs/specs/ (microsoft/typespec)packages/azure-http-specs/specs/ (Azure/typespec-azure)If the Spector case comes from a PR that hasn't been released yet, you must bump the spec dependency in packages/http-client-python/package.json:
Azure/typespec-azure cases: update @azure-tools/azure-http-specsmicrosoft/typespec cases: update @typespec/http-specsTo find the latest dev version, check npm:
npm view @azure-tools/azure-http-specs versions --json | tail -5
npm view @typespec/http-specs versions --json | tail -5
Pick the newest version that includes the Spector case you need. Prefer a stable version (e.g., 0.1.0-alpha.38) if one exists; only fall back to a -dev.X version (e.g., 0.1.0-alpha.38-dev.2) when no stable version contains the change yet.
Example 1 — a newer stable version is available:
// Before
"@azure-tools/azure-http-specs": "0.1.0-alpha.37",
// After (stable 0.1.0-alpha.38 exists and includes the case)
"@azure-tools/azure-http-specs": "0.1.0-alpha.38",
Example 2 — no new stable, only a dev version:
// Before
"@azure-tools/azure-http-specs": "0.1.0-alpha.37",
// After (0.1.0-alpha.38 does not exist yet, use dev)
"@azure-tools/azure-http-specs": "0.1.0-alpha.38-dev.2",
Same pattern applies to @typespec/http-specs.
After bumping, run npm run install under packages/http-client-python to update the lock file.
Write the python test in:
packages/http-client-python/tests/mock_api/azureYou may need either:
.../mock_api/shared.../mock_api/azure AND .../mock_api/unbrandedDecide with this concrete check:
packages/http-client-python/tests/generated/azurepackages/http-client-python/tests/generated/unbrandedmock_api/shared.mock_api/azure and mock_api/unbranded.Why: both azure and unbranded tox runs include mock_api/shared, so shared tests are preferred when they can import the same generated package.
Generated code is gitignored (packages/http-client-python/tests/generated/). You must regenerate the specific spec before writing tests.
Compile only the single spec you need (example for azure-core-page):
cd packages/http-client-python
npx tsx ./eng/scripts/ci/regenerate.ts --flavor azure --name azure/core/page
The --flavor flag selects azure or unbranded. The --name flag is a case-insensitive substring match on the package name.
> ⚠️ Do NOT run npx tsx ./eng/scripts/ci/regenerate.ts without --name — it compiles ALL specs and takes 40+ minutes. Only regenerate the specific spec you need.
> ⚠️ Do NOT use npm run regenerate -- --flavor ... — npm may strip the flags. Use npx tsx directly.
Verify the generated client has the expected method:
grep -r "method_name" tests/generated/azure/ < package-name > /
test_*.py when it already imports the same generated module.asynctests/.mock_api/azure/test_<area>.py, also extend mock_api/azure/asynctests/test_<area>_async.py (or create it if missing).mock_api/shared/test_<area>.py, also extend mock_api/shared/asynctests/test_<area>_async.py.mock_api/unbranded/test_<area>.py, also extend mock_api/unbranded/asynctests/test_<area>_async.py.test_<area>.py and also create the async counterpart under asynctests/.Conventions to match:
pytest.client() fixture that constructs the generated client and yields it via context manager.async def client() fixture + async with ... and mark tests with @pytest.mark.asyncio.list(...) for paged results).Practical guidance:
models.Foo(...)) when the SDK returns models.list(...)) before asserting.result = [item async for item in client.list(...)].assert client.foo.get() == model; client.foo.put(model)).Async client import patterns (match the folder you’re writing to):
aio submodule alongside models, e.g. from specs.<...> import models, aio, then async with aio.<Client>() and await client.<op>(...)..aio modules, e.g. from <pkg>.aio import <Client>.Default: do NOT add new dependencies.
Only if your new/extended test imports a package not already available:
packages/http-client-python/tests/requirements/:base.txt — shared dependencies (pytest, pytest-asyncio, etc.)azure.txt — Azure-specific dependencies (azure-core, azure-mgmt-core)unbranded.txt — unbranded-specific dependencies (corehttp)Avoid adding dependencies unless strictly required by the test.
Format any python files you changed using Black with the project's shared config:
cd packages/http-client-python
python -m black ./eng/scripts/ci/config/pyproject.toml < paths > --config
Replace <paths> with the specific files and/or folders you modified (relative to the http-client-python root).
Alternatively, you can format all test files via the npm script:
npm run format -- --generator
Before opening a PR, run your new or updated test. You will need two terminals: one to run the Spector mock API server, and another to run pytest.
azureunbranded cd packages/http-client-python
npx tsx ./eng/scripts/ci/regenerate.ts --flavor <azure|unbranded> --name <spec-name>
cd packages/http-client-python/tests
python -m venv .venv
# Windows:
.venv\Scripts\activate
# Linux/Mac:
source .venv/bin/activate
pip install -r requirements/base.txt
pip install -r requirements/<azure|unbranded>.txt
# install only a single generated SDK:
pip install --no-deps -e generated/<flavor>/<sdk-folder-name>
cd packages/http-client-python
npx tsp-spector serve node_modules/@azure-tools/azure-http-specs/specs/ node_modules/@typespec/http-specs/specs/
Wait until you see the server listening message before running tests.
cd packages/http-client-python/tests
pytest mock_api/ < azure | unbranded | shared > / < test_file > .py -v
Verify that all tests pass before proceeding.
> Important: If you only added or changed test files, confirming the changed test passes is sufficient. However, if you modified emitter source code (under generator/ or emitter/), you must run the full test suite for the affected flavor(s) to catch regressions before proceeding.
Create a changelog file under .chronus/changes/ to document the change. The file should be a Markdown file with YAML frontmatter specifying the change kind and affected package(s).
File naming convention: <short-description>-<YYYY>-<M>-<DD>-<H>-<m>-<s>.md
Template:
---
changeKind: internal
packages:
- "@typespec/http-client-python"
---
<Brief description of what was added or changed.>
Available changeKind values:
| Kind | When to use |
| -------------- | ------------------------------------------------ |
| internal | Internal changes not user-facing (most test PRs) |
| fix | Bug fixes to existing features |
| feature | New user-facing features |
| deprecation | Deprecating an existing feature |
| breaking | Breaking changes |
| dependencies | Dependency bumps |
For test additions, use changeKind: internal and list @typespec/http-client-python as the package.
package.json/package-lock.json (if dependency versions were updated).npm run regenerate without --name for verification — CI will handle full regeneration.Take microsoft/writing-python-sdk-spector-mock-api-tests from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip, npm, npx.
Without those the skill loads but fails at the first command.