If you've set up WireMock in a CI pipeline before, you know the pattern: pull a Docker image with a full JVM in it, wait for it to boot, configure stubs via a REST API or a pile of JSON files, then tear it down. For a Python project, that's a second language runtime in your pipeline purely to answer GET /users with a canned response.
Mimicker is a Python-native alternative. It's a plain pip install, it starts in-process or via a one-line CLI call, and it has no JVM, no native dependencies, and no heavy runtime — just two small pure-Python libraries (PyYAML for config, colorlog for output).
The Python DSL
from mimicker.mimicker import mimicker, get
mimicker(8080).routes(
get("/hello").body({"message": "Hello, World!"}).status(200)
)
That's a running mock server on port 8080. No config file, no separate process to manage if you don't want one.
The same thing in YAML
For when you want stubs defined outside your test code, useful if QA or frontend devs need to spin up a mock without touching Python:
# stubs.yaml
routes:
- method: GET
path: /hello
status: 200
body:
message: Hello, World!
mimicker serve --config stubs.yaml
Where WireMock still wins
WireMock is mature, has a huge feature set (request matching on nearly anything, record-and-playback, fault injection, a proper admin API), and if you're already in a JVM shop, it's a known quantity. Mimicker doesn't try to match that surface area — it's intentionally smaller.
Where mimicker is a better fit
You're testing a Python service, you don't want a second runtime in CI, and you want stub definitions your whole team can read without learning WireMock's JSON mapping format.
Using it in CI
There's an official GitHub Action:
steps:
- uses: actions/checkout@v4
- uses: mimickerhq/mimicker-action@v1
with:
config: stubs/api.yaml
- name: Run tests
run: pytest
It also ships something WireMock doesn't have out of the box: a stub coverage report. After your tests run, it tells you which stubs were actually hit, so if you delete an endpoint from the real API and forget to update the stub, you find out in CI instead of in production three weeks later.
- name: Mimicker coverage report
if: always()
run: bash ${{ steps.mock.outputs.report-script }}
Add fail-on-unused: true and the job fails outright if a stub goes stale.
Try it
Mimicker is at github.com/mimickerhq/mimicker, docs at mimickerhq.github.io/mimicker. It's still small — if you try it and something's missing for your use case, that's exactly the kind of issue I want to hear about.
Top comments (0)