# I test the operation, not the component.

Why real databases, roles, queues, storage, and browser actions belong in the acceptance path for operational software.

- **Canonical URL:** https://vidhata.me/notes/i-test-the-operation-not-the-component
- **Author:** Vidhatanand V. (Vid)
- **Role:** Fractional CTO and AI Systems Architect

**Published:** 04 Sep 2026 | **Reading time:** 9 minute read

## Why I hold this position

A unit test can prove that a function behaves correctly with the values placed in front of it. It cannot prove that the user can sign in, load the right tenant, create a record, trigger a worker, store an artefact, refresh the page, and still see the same truth through the permissions they actually hold.

I learned to make at least one important journey cross the real system. That does not mean every test must be slow or every external provider must be live. It means the acceptance bar for an operational product cannot stop at isolated components. The product is the path through contracts, state, infrastructure, and human actions.

## A passing component can still participate in a broken journey.

The database schema can be valid while the application sends an old field name. Authentication can work while the tenant header is missing. An API can return the expected shape while a queue worker reads a different version. A browser component can render perfectly against fixtures while the real endpoint rejects the action or returns no data after a migration.

AI systems add more seams. A run may persist metadata but lose the artefact. A model call may succeed while cancellation continues spending money. A generated object may satisfy its schema but fail the policy that makes it usable. Each local success can be genuine, yet the operation can still be false.

## I build one real path through the system.

For the critical journey, I prefer a temporary real database with migrations applied, deterministic seed data, the real API process, the real queue where one exists, and the actual browser application. The test signs in as a real role and uses the same routes and contracts as the user. Object storage and cache services are included when the journey depends on them.

This path stays narrow. It does not need to reproduce every production scale condition. Its purpose is to catch disagreement among the parts. A small, reliable end-to-end gate often finds more consequential failures than a much larger collection of mocked tests because it asks the system to operate, not merely to compile.

## I test the actions that alter state.

Read-only route checks are useful, but they are not enough. I test creation, editing, duplicate conflicts, lifecycle transitions, deletion rules, exports, retries, cancellation, supervisor overrides, and idempotent synchronisation. I want to see the second request as well as the first, because distributed systems often fail when an apparently harmless retry creates a second action.

Roles matter in the same way. An administrator, author, supervisor, operator, and auditor should not see interchangeable systems. The acceptance path needs to prove both permission and denial. A button hidden in the interface is not an authorisation boundary, and an endpoint that returns a friendly error after already changing state is not a safe failure.

## A smoke gate is an operating contract.

The best smoke suites are readable enough to tell the team what the product promises. They verify that the expected services are running on the expected ports, that the browser did not load a different local application, that seeded data belongs to the intended environment, and that pages do not fall back to placeholder or runtime-error states.

I also include the surfaces people experience but backend tests miss: responsive layouts, keyboard access, console errors, horizontal overflow, and the action menu that reaches a less common workflow. The suite should remain small enough to run before handoff and after meaningful changes. Its value is not the number of assertions. Its value is that a passing result means one real operation still works.

## What I take into the next build

- Choose one consequential user journey and run it through real services.
- Test state-changing actions, retries, denial, and recovery.
- Use mocks for isolation, not as the final proof of operation.
- Keep the smoke gate readable, deterministic, and cheap enough to run often.

## Continue reading

[All Fractional CTO field notes](https://vidhata.me/notes)

## Work with Vid

Start with the actual technical pressure: [bring the problem](https://vidhata.me/hire).
