In recent years, one thing has become obvious to me: writing API tests is not the hard part.
Keeping them useful is.
On different projects, I kept seeing the same three problems appear repeatedly. None of them were caused by bad tools or poor developers. They were simply the result of APIs evolving faster than the tests surrounding them.
These are the three changes that made the biggest difference for us.
1. Stop treating your API specification as documentation
For a long time we maintained three different versions of the same API:
- OpenAPI documentation
- Test cases
- Mock answers
In the end they separated.
Someone would update the API but forget to update the tests.
Or the documentation.
Or the teasing.
Instead, we started treating the OpenAPI specification as the source of truth.
The API changes once.
Everything else follows.
Even if you don’t automatically generate tests, having a canonical contract drastically reduces maintenance.
2. Separate contract testing from business testing
One mistake we made early on was subjecting all claims to the same test.
For example:
Create Customer
↓
Status = 201
↓
Schema Valid
↓
Business Rules
↓
Database Validation
When the test failed, it took time to find the real cause.
Instead, we now divide responsibilities.
Contract tests
- Status codes
- Headers
- Required fields
- Response scheme
Commercial tests
- Prices
- Permissions
- Validation rules
- Workflows
Testing became much easier to understand and maintain.
3. Don’t make fun of everything
For a time we scoffed at all external dependence.
The test suite was fast.
He was also overconfident.
Over time, we discovered that several production failures were due to assumptions that our simulations never put into practice.
Today we used three layers.
- **Unit Testing – **Simulates everything.
- **Integration tests: **Only simulations of systems that we do not control.
- **Pre-release validation: **Run a small suite with real services or official sandboxes.
It’s slower, but it catches problems that perfect mocks will never catch.
A lesson I didn’t expect
Authentication testing now consumes more CI time than almost anything else.
OAuth flows, token refreshes, service accounts, rotating secrets… are all necessary, but they are also expensive to test correctly.
I’m curious how other teams are handling this today.
Are you:
- Try a real identity provider?
- Doing a local drill?
- Using pregenerated tokens?
- Doing something completely different?
I’d also be interested to know how you approach cursor-based pagination and how you test third-party APIs, e.g. Stripe or Twilio, etc.
Each team seems to have a different answer and I suspect there is no single “best” solution.




