Your AI agent can write the tests. Can it run them?
Ask Claude Code or Cursor to write an integration test and you will get something that looks right. Correct imports, sensible structure, reasonable assertions.
Then you run it and it fails, because the agent was writing against an imagined system rather than the one you have. It guessed the service name, the port, the shape of the response. It had no way to check.
The bottleneck in AI-assisted testing is not generation. It is verification.
The loop that is missing
A human writing an integration test does something the agent usually cannot: they run it, read the failure, and adjust.
That loop needs four capabilities. Write the test. Execute it against a real environment. Observe what actually happened. Change the test and repeat.
Most agent setups only have the first. The agent produces a file and hands it to you. You run it, paste the error back into the chat, the agent guesses again. You are the integration layer, manually shuttling context between the thing that writes and the thing that runs.
That is slow, and it caps how useful the agent can be.
Why integration tests are the worst case for this
Unit tests are relatively easy for an agent. The context needed fits in the file, and the failure is usually explicable from a stack trace.
Integration tests are the opposite. To know why one failed, you need to know what request one service sent another, what the database returned, whether the mocked third party responded as expected, and what the browser was showing at the moment the assertion ran.
None of that is in a stack trace. It is spread across four layers, and if the agent cannot see them, it is debugging blind.
What changes with tool access
Dokkimi ships an MCP server that auto-registers with Claude Code, Cursor and GitHub Copilot on install. No configuration.
That gives the agent the whole loop as native tool calls rather than shell commands it has to parse:
Writing - get_reference returns the definition spec, so the agent writes against the real schema instead of guessing. list_fragments shows the shared service definitions already in the project, so it reuses postgres-db.yaml rather than inventing one. validate_file catches errors before anything runs.
Running - run_tests executes, watch_run follows live status, get_run_summary returns results.
Debugging - this is where it matters. get_failures for what broke, then get_traffic for the actual HTTP calls between services, get_db_logs for what the database was asked, get_console_logs for the browser side. diagnose runs automated root-cause analysis. diff_traffic compares two runs, which is usually the fastest way to find why a passing test started failing.
Environment - status, doctor, stop, clean, reboot, plus config read and write.
The practical difference: the agent writes a test, runs it, sees that the order service returned 500 because the mock was matching on the wrong path, fixes the mock, runs again, and reports back once it is green. You review the result rather than relaying error messages.
Why the format matters
Dokkimi tests are declarative YAML or JSON. That is a deliberate choice for this.
Agents are reliable at producing structured configuration against a known schema. They are less reliable at writing imperative test code that has to be correct in every detail, because there are more ways to be subtly wrong and the failure modes are harder to inspect.
A definition file also means the agent can read the existing suite and understand it. Thirty YAML files with shared $ref fragments is a structure it can reason about. Thirty files of bespoke container orchestration code is not.
What this looks like
You can paste a dokkimi dump into a conversation and the agent has full context on the environment. Or just describe what you want:
"Write a test for the checkout flow. It should mock Stripe returning a declined card, assert the UI shows the failure state, and confirm the order row is marked payment_failed rather than confirmed."
The agent looks up the spec, checks which shared fragments exist, writes the definition, validates it, runs it, and iterates against real failures until it passes.
The resulting file is one you would have written:
name: checkout-declined-card
items:
- $ref: ../shared/web-app.yaml
- $ref: ../shared/order-service.yaml
- $ref: ../shared/postgres-db.yaml
- $ref: ../shared/mock-stripe.yaml
tests:
- name: Declined card leaves the order unpaid
steps:
- action:
type: ui
url: http://web-app:3000/checkout
subSteps:
- action: click
selector: '[data-testid="pay"]'
- action: waitForSelector
selector: '[data-testid="payment-failed"]'
- action:
type: dbQuery
database: postgres-db
query: "SELECT status FROM orders ORDER BY created_at DESC LIMIT 1"
assertions:
- path: $.response.data[0].status
operator: eq
value: 'payment_failed'The part worth being careful about
An agent that can write and run tests can also write a test that passes for the wrong reason.
Weakening an assertion until it goes green is a valid-looking way to fix a failure, and an agent optimising for a passing suite will sometimes take it. Review what the test asserts, not just whether it passed. That is true of human-written tests too, but the volume changes when generation is cheap.
The other risk is a test suite that grows faster than anyone's understanding of it. Shared $ref fragments help, because the environment definitions stay in one reviewable place even as the number of test files grows.
Setting it up
brew install dokkimi/tap/dokkimi
# or
npm install -g dokkimiThe MCP server registers with Claude Code, Cursor and Copilot on first run. Then:
dokkimi init # scaffolds .dokkimi/ with examples
dokkimi doctor # verify Docker and NodeNode 20+ and Docker required. Free locally and in CI.
Ask your agent to write a test definition for a flow in your app and see what it produces. It has the spec.
Docs at dokkimi.com/docs.