Five Kinds of API Test and When Each One Earns Its Place
The five types of API testing that do most of the work: functional, integration, regression, load and security. What each catches, what each misses, how to spread your effort, and the one-minute check OWASP ranks as the top API risk.
Jul 7, 202611 min read

The short answer on types of API testing
There are many named types of API testing, but five do almost all the useful work: functional, integration, regression, load and security. Each answers a different question, costs a different amount and misses a different set of problems. When someone says "the API is tested", they usually mean one or two of these, which is why two engineers can both be telling the truth and still disagree about whether something is ready.
I am a Lead Full Stack Engineer, and the most valuable testing habit I know is not a tool. It is being able to say exactly which kinds of test you have run, and therefore which kinds of problem could still be waiting. This post walks through the five, what each catches, what each structurally misses, how to spread your effort, and the one-minute authorisation check that finds the API vulnerability OWASP ranks first.
| Type of API test | Question it answers | Typical cost | What it misses |
|---|---|---|---|
| Functional | Does this endpoint do what it says? | Low | Anything involving real dependencies |
| Integration | Does it work with the real database, cache and queue attached? | Medium | Behaviour under load, real third parties |
| Regression | Did we break something that used to work? | Grows over time | Anything nobody wrote a test for |
| Load | Does it hold up under realistic traffic? | Medium to high | Almost everything, if traffic is unrealistic |
| Security | Can this be misused? | Varies | Unknown patterns; a clean scan is not proof |
You will also see smoke, contract, fuzz, validation and end-to-end tests in other lists. They are real and useful, and I place them inside these five below rather than treating each as a separate discipline.
Functional API testing: does this endpoint do what it says?
Send a request, check the response. Correct status code, correct body shape, correct values. Then send bad input and check you get a sensible error rather than a stack trace.
What it catches: the endpoint returning the wrong thing, missing validation, error cases nobody implemented.
What it misses: anything involving another system. Every dependency here is usually a mock, and a mock is a statement about how you believe the other system behaves, which may not be true.
Where to spend your effort: the unhappy paths. Everybody tests that a valid request works. Far fewer test a missing required field, a string where a number belongs, an identifier that does not exist, an empty list, or a request body twice the expected size. That is where the bugs live.
A few practical notes:
- Test the contract you publish. If you have an OpenAPI specification, validate responses against it automatically.
- Check error formats as carefully as success. Clients depend on error shapes too.
- Smoke tests belong here. A handful of functional checks run right after every deploy is the cheapest early warning you will ever get.
Tools like Postman are fine for exploring, and your language's normal test runner, such as pytest or Vitest, is better for anything you want to keep and run in CI.
API integration testing: does it work with the real things attached?
Same requests, but now against a real database, a real cache and a real message queue.
What it catches: the large category of problems that only exist between components. A migration that never ran. A transaction that does not roll back the way you assumed. A query that is fine against ten rows and unusable against a million. Serialisation differences that mocks hid. A unique constraint your code never expected to hit.
What it misses: load-related behaviour, and third parties you are still not really calling.
The trade-off: slower and more annoying to set up. Containers have made it far less painful: Testcontainers is an open source library that gives your tests lightweight, throwaway instances of databases, message brokers and anything else that runs in Docker, created at the start of a test run and removed at the end.
Keep far fewer of these than functional tests. Martin Fowler's Practical Test Pyramid sums up the shape: lots of small, fast tests, some more coarse-grained ones, and very few high-level end-to-end tests. Integration tests are for the interactions, not for re-checking business logic you already covered.
Contract tests: integration testing between services
If your API is consumed by other services, contract tests sit here too. Rather than spinning up every service for an end-to-end run, the consumer records what it expects and the provider verifies it can satisfy that. Pact is the common tool, and it catches the specific failure distributed systems introduce: one team changing a field another team depends on. More on this in microservices practices that keep them workable.
API regression testing: did we break something that used to work?
Regression testing is less a separate style of test than a discipline: keep the tests, and run all of them on every change.
What it catches: the most common failure in a maturing codebase, a fix over here quietly breaking something over there.
What it costs: the suite grows and grows. Eventually it takes long enough that people stop running it locally, and at that point it has stopped protecting you.
How to keep it honest:
- Every bug fix ships with the test that would have caught it. That single habit builds a suite that reflects your real failure history rather than what someone imagined in advance.
- Delete tests that no longer test anything real. A suite nobody trusts gets skipped wholesale.
- Fix flaky tests immediately or quarantine them. One test that fails randomly teaches everyone to ignore red builds.
- Run it in the pipeline, not just on laptops. I walk through where tests sit in what happens between your pull request and production.
API load testing: does it hold up under traffic?
Send realistic traffic at a realistic rate and watch response times, error rates and resource use.
What it catches: the connection pool that is too small, the missing index nobody noticed at low volume, the memory that grows and never comes back, the timeout that turns a slow dependency into a full outage.
What it misses: almost everything, if the traffic is not realistic. This is the trap. Hitting one endpoint with identical requests warms every cache and tells you nothing. Real traffic is mixed, uneven, spiky and full of cache misses.
The number that matters: not the average. Averages hide the problem. Look at the 95th and 99th percentile latency, because that is the experience of the users having a bad time, and they are the ones who leave.
Load testing itself has sub-types. The Grafana k6 documentation lays them out clearly:
| Load test type | What it does |
|---|---|
| Smoke | Checks the script works and the system copes with minimal load |
| Average load | Tests behaviour under typical expected traffic |
| Stress | Pushes load above the expected average to see how the system behaves at its limits |
| Soak | Runs for an extended period to find leaks and slow degradation |
| Spike | Simulates a sudden, short, massive jump in traffic |
| Breakpoint | Increases load gradually until the system hits its capacity limit |
k6 is free and scriptable in JavaScript, which makes it a good first tool. If you want a project that forces you to learn this properly, try the HTTP server from raw sockets with a load test report or the URL shortener with a load test report.
API security testing: can this be misused?
Authentication actually enforced. Authorisation checked on every route rather than most of them. Input handled safely. Rate limits present. Secrets absent from logs and error responses.
What it catches: the failure where the feature works perfectly and that is the problem, because it works perfectly for someone who should not have access.
What it misses: it cannot prove there is nothing there. A clean scan means known patterns are absent, not that the system is safe.
Fuzz testing belongs here too. Throwing malformed, oversized and unexpected input at an endpoint finds crashes and injection points that hand-written cases never think of.
The one-minute check: broken object level authorisation
Take a valid request from user A. Change the identifier in the path to one belonging to user B. Send it. If it returns B's data, you have found the vulnerability that tops the OWASP list for APIs.
This is not my opinion. It sits at number one in the OWASP API Security Top 10 (2023) as API1: Broken Object Level Authorization, where attackers manipulate the ID of an object sent in a request to reach data they should not see. OWASP's own example is an endpoint like /shops/{shopName}/revenue_data.json where changing the shop name exposes other stores' sales.
The fix is a server-side check, on every request, that the authenticated user is allowed to access that specific object. Not just that they are logged in. The OWASP API Security Top 10 is short enough to read in an afternoon, and PortSwigger Web Security Academy lets you practise these attacks legally. If security interests you as a career, read getting into cybersecurity as a fresh graduate.
How to spread your effort across the types of API testing
A rough shape that works for most teams:
- Many functional tests. Fast, cheap, run constantly, covering unhappy paths thoroughly.
- Some integration tests. Covering the interactions between components, not the logic again, plus contract tests if other services consume you.
- A few load tests. Before major releases and whenever you change something that touches data volume or hot paths.
- Security checks automated in the pipeline, plus the manual authorisation check above on anything new that returns user data.
- All of it kept and re-run on every change, which is the regression part.
The mistake to avoid is spending three weeks writing exhaustive tests against mocks, reaching a coverage number that looks excellent, and shipping something that has never once talked to the real database. Coverage measures which lines ran. It does not measure whether you tested anything that matters.
Good tests also start with good design. An API with consistent resource naming, predictable errors and clear versioning is much easier to test. Grokking Modern API Design Interview is a solid structured course on designing APIs well, and the free Microsoft REST API Guidelines and Zalando RESTful API Guidelines are worth reading alongside it.
The habit worth building
Before you call something tested, ask which of the five you actually ran, and then say out loud what class of problem is still possible.
"I have functional tests passing, so the logic is right, but this has never been run against real data volumes" is a genuinely useful sentence. It is honest, it tells your team where the risk is, and it is a great deal better than "yes, it is tested". Engineers who talk like this get trusted with bigger things, which is part of what I describe in what makes a good software engineer beyond writing code.
Learn it on Sefism
- Backend roadmap and the backend cheat sheet
- Grokking Modern API Design Interview for designing APIs that are easy to test
- OWASP API Security Top 10 and Pact documentation
- Grafana k6 documentation for load testing
- QA test suite for an open source web app as a portfolio project
- Sixteen things that break a backend
FAQ
What are the main types of API testing?
Functional, integration, regression, load and security testing cover most of the value. Smoke, contract and fuzz testing are useful variants that fit inside those five.
What is the difference between API functional and integration testing?
Functional tests check an endpoint's behaviour, usually with dependencies mocked. Integration tests run the same requests against real databases, caches and queues to catch problems between components.
Which tool is best for API testing?
Postman is good for exploring, your language's test runner (pytest, Vitest, JUnit) is best for automated tests, k6 for load testing and Pact for contract testing. The type of test matters more than the tool.
What is the biggest API security risk?
Broken object level authorisation, ranked first in the OWASP API Security Top 10 (2023). It happens when an API returns an object without checking that the caller is allowed to access that specific object.
How many API tests should I write?
Many fast functional tests, fewer integration tests, a handful of load tests and automated security checks. Add a regression test every time you fix a bug.
Ask your own question
If your situation is different from the ones above, the career questions library has honest answers to the questions students and engineers ask me most.
Want a learning roadmap built around you, written answers to your own questions and a place to discuss your FYP? Create your free Sefism account. Members can also book a one to one session when they want to talk it through.
Stay in touch
- LinkedIn: where I share roadmaps, career advice and honest takes on hiring. Follow, or message me.
- X (Twitter): short practical thoughts on engineering and careers.
- Instagram: quick tips and a more personal side.
- Sefism Discord: meet other students and engineers working through the same job market and share what is working.
- Sefism on YouTube: walkthroughs and talks.
Comments (0)
Comments are closed for now.
No comments yet.