Most API bugs are not exotic: a missing field, a wrong status code, a timeout under load, or a breaking contract that shipped because nobody verified it. Ad-hoc testing catches some of these by luck. An API testing strategy catches them on purpose.
.
Example request:
GET /api/users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
Useful assertions:
- Status is
200
- Body matches the
Userschema
idequals42
emailis a valid email string
Functional tests should be automated early for every important endpoint.
Integration Testing
Integration testing verifies that your API works with real dependencies such as:
- Databases
- Message queues
- Payment providers
- Internal downstream services
A functional test can pass with a mock and still fail when the real dependency is connected. Integration tests close that gap.
See for how to structure this.
Contract Testing
Contract testing verifies that API providers and consumers agree on request and response shapes.
It catches breaking changes such as:
- Renamed fields
- Removed fields
- Type changes
- Changed enum values
- Removed endpoints
- New required request fields
If other teams, apps, or customers consume your API, contract testing is essential.
Read more in for options.
Security Testing
Security testing verifies that your API rejects unsafe or unauthorized requests.
Cover:
- Missing tokens
- Expired tokens
- Wrong scopes
- Access to another user’s data
- Injection attempts
- Unsafe input
- Sensitive data exposure
Every endpoint that handles sensitive data needs authentication and authorization checks.
See .
Make tests independent
Each test should set up its own state.
Avoid this pattern:
Test B depends on an ID created by Test A
Prefer this:
Scenario:
1. Create user
2. Capture userId
3. Fetch user by userId
4. Assert response
5. Delete user
Passing values inside a scenario is fine. Depending on global execution order is not.
Isolate environments
Keep separate environments for:
- Local development
- CI
- Staging
- Production
Store environment-specific values separately:
- Base URL
- Tokens
- User credentials
- Feature flags
- Tenant IDs
The same test should run against a different environment by swapping variables, not editing the test.
For environment planning, see for the full case.
Automating Tests in CI
A testing strategy is only useful if it runs without manual effort.
A practical CI setup has three layers.
1. Every push
Run fast checks:
- Functional tests
- Contract tests
- Lightweight regression tests
Fail the build if any assertion fails.
2. Nightly or pre-release
Run slower suites:
- Integration tests
- End-to-end workflows
- Load tests
- Security tests
3. Always publish reports
Use machine-readable output such as JUnit XML so your CI system can show:
- Pass count
- Failure count
- Failed test names
- Trends over time
A minimal GitHub Actions job:
name: api-tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Run API tests
run: npm test
The command depends on your tooling, but the pattern is the same:
- Check out the code.
- Set up the runtime.
- Run the suite.
- Let a non-zero exit code fail the build.
- Publish a report.
For a deeper CI setup, including caching, secrets, and reporting, see how to automate API tests in CI/CD.
How Apidog Fits Into the Strategy
The strategy above is tool-agnostic. You can build it with separate tools for design, testing, mocking, and documentation.
The tradeoff is drift: the spec, tests, mocks, and docs can fall out of sync.
Apidog keeps these in one place:
- Design the API contract
- Write test scenarios against it
- Generate mocks from the same schema
- Publish documentation from the same source of truth
That helps make contract testing and shift-left testing part of the default workflow instead of extra work.
For CI, the Apidog CLI runs saved test scenarios and suites headlessly. It is a Node package, so it fits into CI systems that can run Node.
Install it:
npm install -g apidog-cli
Run a saved scenario or suite:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
Flags:
--access-token: authenticates the run. Store this as a CI secret.
-t: scenario, folder, or suite ID to run.
-e: environment ID.
-r: reporters, such ascli,html,json, andjunit.
Use junit for CI dashboards and html for human-readable reports.
For a data-driven run:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioId> \
-e <environmentId> \
-d ./data/users.csv \
-r cli,junit
You can also use:
--upload-reportto upload the report to the cloud
--branchto run against a specific branch
The Apidog CLI runs saved Apidog scenarios and suites. It is not an interactive request sender or a load generator, so use a dedicated load testing tool for the performance layer.
A Starter Strategy Checklist
Use this checklist to build your API testing strategy incrementally.
- [ ] Rank endpoints by business risk and traffic.
- [ ] Add positive functional tests for the highest-risk endpoints.
- [ ] Add at least one negative test per endpoint.
- [ ] Add edge-case tests for lists, numbers, dates, and free text.
- [ ] Add contract tests for APIs consumed by other teams or customers.
- [ ] Add integration tests for flows that cross services.
- [ ] Separate local, CI, staging, and production environments.
- [ ] Store base URLs, tokens, and IDs as environment variables.
- [ ] Use generated or seeded test data.
- [ ] Keep tests independent.
- [ ] Run fast tests on every push.
- [ ] Fail the build on test failure.
- [ ] Schedule slower integration, load, and security suites.
- [ ] Publish JUnit reports in CI.
- [ ] Review and update the suite when the API changes.
- [ ] Delete tests for removed endpoints.
You do not need everything on day one. Start with functional and negative tests for your highest-risk endpoints, run them in CI, then expand coverage outward.
FAQ
What is the difference between an API testing strategy and a test plan?
A strategy is the high-level approach: which test types you use, which layers they run at, and when they execute.
A test plan is specific to a release or feature. It lists the exact endpoints, cases, data, and pass criteria.
The strategy stays relatively stable. The plan changes per release.
How many tests should be at each layer of the pyramid?
There is no fixed ratio.
The shape matters more than the exact count:
- Many fast single-request tests
- Fewer integration and contract tests
- A small number of end-to-end workflow tests
If slow top-layer tests outnumber fast bottom-layer checks, rebalance.
Do I need contract testing if I already have functional tests?
Yes, if other teams, applications, or customers consume your API.
Functional tests verify endpoint behavior. Contract tests verify that the interface has not changed in a way that breaks consumers.
An endpoint can still “work” while breaking clients that depend on a specific field, type, or schema.
How often should I run load tests?
Run load tests:
- Before launch
- Before known traffic spikes
- Weekly or monthly to catch performance drift
Do not run heavy load tests on every commit. Keep fast tests in CI and run load tests separately.
Can I automate the whole strategy in CI?
You can automate the repeatable parts.
Functional, integration, contract, and regression tests usually run well in CI and can gate merges.
Load and security testing often run on a schedule or in dedicated infrastructure because they are slower or more resource-intensive.
A headless runner such as the Apidog CLI can execute saved API test scenarios on every push.
SOCIAL SHARE CARD GENERATOR