petrkindlmann/qa-skillsMIT7 files

Service Virtualization

>-

Specification
Skill ID
petrkindlmann/qa-skills/service-virtualization
Publisher
petrkindlmann
Repository
qa-skills
Installs
0
Files
7
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

petrkindlmann/qa-skills/service-virtualizationInstalls these files
  • SKILL.md
  • references/ci.md
  • references/msw.md
  • references/record-replay.md
  • references/testcontainers.md
  • references/toxiproxy.md
  • references/wiremock.md

What this skill tells the agent

<objective> Mock Stripe at the SDK layer and your tests pass green while production 500s the moment Stripe changes a response field — because the stub was never tied to a contract. This skill picks the right isolation strategy per dependency (in-process mock, HTTP stub, record-replay, fault injection, or ephemeral real service), stubs at the HTTP layer so tests survive SDK upgrades, and makes the CI run fail when any real call escapes the stubs. </objective>

Quick Route

SituationGo to
Node/browser test hitting an external HTTP APIMSW → references/msw.md
Polyglot CI, complex matching, or you need a standalone stub serverWireMock → references/wiremock.md
Dependency is a DB / cache / queueTestcontainers → references/testcontainers.md
Testing timeouts, latency, connection resetsToxiproxy → references/toxiproxy.md
Bootstrapping stubs from a real API, or a multi-step baselineRecord-replay → references/record-replay.md
Wiring any of these into GitHub Actionsreferences/ci.md
Not sure which to reach forDecision Tree (below)

Discovery Questions

Check .agents/qa-project-context.md first — if it exists, use it, respect existing mocking conventions, and skip anything answered there. Then:

  • How many external dependencies does the system call, and which are painful in tests? Rate-limited, slow, flaky, or paid dependencies are the highest-priority virtualization candidates; list payment, email, auth, and third-party data sources.
  • What testing levels need isolation? Unit tests want fast in-process mocks; integration tests want HTTP-level stubs; E2E wants real or containerized services — the level sets the strategy.
  • Does the provider offer an official test mode or sandbox? Stripe test mode, Twilio test creds, etc. beat any home-grown stub for fidelity — prefer them where they exist.
  • Do you have contracts with these dependencies? If yes, contract tests keep stubs in sync; see contract-testing. If no, mocking what you don't own is a known risk (Core Principle 3).
  • Docker available in CI? No Docker steers you to MSW (in-process); Docker unlocks WireMock, Testcontainers, and Toxiproxy.

Core Principles

1. Match the isolation level to the confidence you need. Unit tests can mock aggressively — they test internal logic. Integration tests should use realistic stubs or real services because they test boundaries. E2E should run the closest thing to production that is still reliable.

2. Real services beat fakes when they're fast, free, and reliable. A local PostgreSQL container gives more confidence than a fake and costs little — prefer it. Reserve fakes for dependencies that are slow, unreliable, or paid.

3. Never mock what you don't own without a contract — and prefer the provider's test mode. If you stub Stripe and Stripe changes its response shape, your tests stay green while production breaks. In order of preference: use the provider's official test mode/sandbox (Stripe test mode, Twilio test creds) → an HTTP stub validated by a contract test for drift → a bare stub only when nothing better exists. See contract-testing.

4. Stubs must fail realistically. A stub that always returns 200 never exercises error handling. Every stub needs error variants: 429 rate limits, 500s, timeouts, malformed bodies.

5. One abstraction layer between test and tool. Wrap MSW handlers, WireMock stubs, and Testcontainers setup behind a consistent interface so switching tools doesn't mean rewriting tests.


Decision Framework

When to use each isolation strategy

StrategySpeedFidelityComplexityBest for
In-process mockFastestLowestTrivialUnit tests, isolating internal modules
HTTP stub (MSW)FastMediumLowFrontend/Node tests hitting external APIs
HTTP stub (WireMock)FastMedium-HighMediumLanguage-agnostic, complex matching rules
Record-replayFast after first runHigh initially, decaysMediumBootstrapping stubs from real APIs quickly
Service fakeMediumHighHighStateful dependencies (in-memory DB, fake auth)
Ephemeral real (Testcontainers)SlowerHighestMediumDatabases, message queues, caches
Shared real serviceSlowProduction-levelLow (to set up)Staging validation, final pre-deploy check

Decision tree

Is the dependency internal to your codebase?
├─ Yes → In-process mock (vi.mock / jest.mock / monkeypatch)
└─ No → Is it a database, cache, or message queue?
         ├─ Yes → Testcontainers (ephemeral real instance)
         └─ No → Is it a third-party HTTP API?
                  ├─ Yes → Does the provider offer a test/sandbox mode?
                  │        ├─ Yes → Use sandbox in staging, MSW/WireMock in CI
                  │        └─ No → MSW or WireMock + contract test for drift detection
                  └─ No → Is it an internal microservice?
                           ├─ Yes → Contract test (Pact) + stub for consumer tests
                           └─ No → Evaluate case by case

Tools

Pick MSW as the default for in-process Node/browser tests; WireMock for cross-language CI or standalone stub servers; Prism when the OpenAPI spec is the contract; Mockoon for dev-time exploratory mocking. Heavy code for each lives in references/ — pointers below.

MSW (Mock Service Worker)

MSW 2.x intercepts HTTP at the network layer (Service Worker in the browser, request interception in Node). The default for JS/TS projects. Stub at the HTTP layer (POST /v1/payment_intents), never at the SDK method — that decouples the test from the SDK version.

The strongest enforcement seam this skill offers: setupServer(...).listen({ onUnhandledRequest }). Set it to "error" in CI so any escaped real call fails the run; "warn" is fine locally while iterating.

See references/msw.md for centralized stateful handlers (payments), the Vitest setup with the CI/local onUnhandledRequest switch, per-test timeout/retry overrides, and a full stateful auth flow (create / verify / refresh / revoke via `http.delete`) keyed on a Bearer token.

WireMock

Language-agnostic HTTP stub server (current stable 3.13.2 — 4.0 is beta-only as of mid-2026, stay on 3.x for CI). Runs standalone or as a Docker container. Best for polyglot environments or complex matching rules.

Use priority-based mappings for error scenarios: a priority: 1 mapping that matches an opt-in header (X-Test-Scenario: rate-limit) and returns 429 shadows the default happy-path mapping only when the test asks for it. WireMock also exposes an admin API for programmatic stub creation (POST /__admin/mappings), verification (POST /__admin/requests/count), and reset (POST /__admin/mappings/reset).

See references/wiremock.md for the Docker setup, a response-templated paginated mapping, the priority error mapping JSON, and the drift-detection seam to contract-testing (replay a Pact or validate the stub against the OpenAPI spec via Prism).

Other HTTP mock servers

ToolStrengthsWhen to use
MockoonDesktop UI + CLI; OpenAPI import; rule-based responses; lightweightDev-time mocking and quick CLI mocks in CI
HoverflyCapture-replay (record real traffic, replay deterministically); capture/simulate/modify/synthesize modesMigrating from a real dependency to a mock — record once, replay forever
PrismOpenAPI-driven mock server (Stoplight); validates requests + generates responses from specOpenAPI-first projects with a published spec
MockServerJava-based; rich expectation matching; multi-protocolJVM teams already on MockServer

Testcontainers

Use this skill in a project

Open any RiverX project, search the Skills panel for petrkindlmann/qa-skills/service-virtualization, and install it in one click.

Use this skill