Unit Testing vs Integration Testing: What Each One Actually Checks
Unit and integration tests are often confused as the same test at different sizes. They answer different questions, and mixing them up creates slow, brittle suites.

An SDET on a payments team once inherited a suite labeled unit tests that took 12 minutes to run because half of them quietly hit a real database. Nobody had planned it that way. Test after test got added to the same file, and nobody stopped to ask whether a given test needed a real database connection or not. That mess is what happens when a team stops distinguishing unit testing from integration testing and just writes tests without thinking about isolation. This post lays out unit testing vs integration testing plainly: what each one actually checks, a concrete example of the same functionality tested both ways, and the mistakes that turn a fast suite into a slow one nobody wants to run.
What is unit testing?
A unit test checks one small piece of code in isolation, usually a single function or class. It asks a narrow question. Does this piece of code do what it claims, given a specific input, without touching anything else.
A unit test for a discount calculation function would call that function directly with a set of prices and a coupon code. It would then check the returned total. It would not touch a database, a network call, or the file system.
Anything the function depends on gets replaced with a fake or a stub. Typical tooling includes Jest, JUnit, and PyTest. These frameworks run entirely in memory, in milliseconds per test.
What is integration testing?
An integration test checks whether multiple components actually work together. It asks a different question. Do these pieces, once connected, behave correctly as a group.
An integration test for the same discount feature might call the actual checkout API. It would let that call hit a real, test only database, apply the coupon, and confirm the order total in the database matches what the API returned.
It exercises the real wiring between the discount function, the order service, and the database layer. Typical tooling includes Testcontainers, Supertest, or a framework's own integration test runner connected to a real or containerized dependency.
Unit testing vs integration testing, side by side
The two levels differ on several practical dimensions.
- Isolation level: a unit test isolates one function or class; an integration test connects several real components.
- Speed: a unit test typically runs in milliseconds; an integration test often takes seconds because it touches real dependencies.
- What a failure tells you: a unit test failure points at one function; an integration test failure points at how pieces interact, which takes more digging.
- Who writes them: developers usually write unit tests alongside the code; both developers and SDETs often write integration tests.
- Where they run: unit tests run on every save or every commit; integration tests often run in CI only, because of setup cost.
A team that tracks both levels against the same feature avoids the common gap where a feature has ten unit tests and zero coverage for how it actually connects to the rest of the system.
A concrete example: testing the same feature twice
Take a checkout flow that applies a 10 percent discount when a coupon code is valid. The unit test calls the applyDiscount function directly with a price of 100 and a valid coupon. It checks that the function returns 90.
No network call happens in that test. No database is touched. The test runs in under a millisecond and fails only if the discount math itself is wrong.
The integration test sends an actual HTTP request to the checkout endpoint with the same coupon. It lets that request hit the real order service and a test database, then checks the order record shows a total of 90.
If this integration test fails, the discount math might still be correct. The failure could instead be a routing bug, a database write that never happened, or a mismatch between the API response and what got saved. That is the real value of the integration test. It catches the kind of bug the unit test cannot see, because the unit test never touches the wiring between pieces.
This pairing shows why teams need both. Nine passing unit tests around a discount function say nothing about whether the checkout API actually calls that function correctly in production.
When to use each: fitting them into a test pyramid
Unit and integration tests are not competing choices. They fit together in a pyramid where each level answers a question the other cannot.
- Write a unit test for logic with clear inputs and outputs, like the discount calculation, a date formatter, or a validation rule.
- Write an integration test for the connections between real components, like an API endpoint writing to a database, or two services calling each other.
- Keep the base of the pyramid wide, meaning many fast unit tests, and the integration layer thinner, meaning fewer slower tests covering the riskiest connections.
A team that inverts this shape ends up in trouble. Picture a suite with hundreds of integration tests and only a handful of unit tests. That suite takes 40 minutes to run and cannot pinpoint failures quickly, because every failure requires digging through several connected services.
A team with only unit tests has the opposite problem. It misses real bugs in how services actually talk to each other. The Safari only checkout bug that reached a customer is a common example: the unit tests for the checkout logic all passed, but nobody had an integration test covering the actual request path a Safari user took.
Common mistakes teams make
The first mistake is writing unit tests that secretly depend on external state. A test labeled unit but calling a real database or a live API is not a unit test anymore, even if it lives in the same file as the real ones.
This kind of test runs slower than it should. It fails when the database is down for unrelated reasons. Worst of all, it gives the team a false sense of isolation, since a failure could mean the logic is wrong or the database connection is flaky.
The second mistake is building integration suites so heavy they never run locally. If a 900 test integration suite takes 50 minutes and needs three services running, developers stop running it before pushing code.
It ends up running only in CI. That means feedback arrives after the code is already merged, not before, which defeats much of the point of having the tests at all.
Both mistakes trace back to the same root cause. Neither team matched the test's isolation level to the question it was supposed to answer. A fast, focused unit test and a slower, broader integration test both earn their place, but only when each one is actually answering the question it was built for.
Questions people ask
Is an integration test just a slower unit test?
No. It is not the same test run bigger. A unit test checks one piece in isolation, while an integration test checks whether real, connected pieces behave correctly together.
Can a unit test call a real database if it is fast enough?
If it touches a real database, it has become an integration test in practice, regardless of speed. The label should follow what it actually depends on, not how quickly it runs.
How many integration tests should a team have compared to unit tests?
There is no fixed ratio, but most healthy suites have far more unit tests than integration tests, following the shape of a pyramid rather than an even split.
Do integration tests replace the need for unit tests?
No. They answer a different question. A team needs both, because a passing integration suite does not guarantee the underlying logic is correct in every case.
Does Tesbo run or execute unit and integration tests?
No. Tesbo manages and documents test cases across both levels. It does not execute automated tests or replace unit and integration test frameworks.
Try Tesbo, or get the next useful idea
Start building your testing workflow now, or get one practical email a month.
Get startedOne email a month
What we shipped, what we learned, and the occasional infographic worth pinning. Unsubscribe in one click.


