Unit tests check a small piece of code in relative isolation; integration tests check whether separate components or a component and its dependencies work together. The boundary varies between teams, so describe what a test exercises and which dependencies are real or replaced instead of relying on its label alone.
What separates a unit test from an integration test?
The main difference is the boundary being tested. A unit test focuses on one small unit of behavior, such as a function, method, or team-defined component. An integration test crosses a boundary: it might connect application components, exercise a request pipeline, or use a database or other infrastructure.
A unit does not have to mean one class. Its useful size depends on how the system is designed; functional, procedural, and object-oriented code may draw that boundary differently. Martin Fowler discusses the variation in his overview of unit tests.
| Dimension | Unit test | Integration test |
|---|---|---|
| Scope | A small unit’s behavior or logic | Interactions across components or an important boundary |
| Dependencies | Often controlled inputs, fakes, or mocks replace collaborators | Often includes real components or infrastructure, though some dependencies may still be replaced |
| Setup and feedback | Usually simpler and faster | Usually requires more setup and processing, and takes longer |
| Confidence gained | Local logic, conditions, and branches | Interfaces, configuration, serialization, infrastructure, and component interaction |
| Common maintenance concern | Tests can become coupled to implementation details | Tests may depend on data, services, and environment setup |
These are common tendencies, not hard rules. Microsoft Learn describes unit tests as checks of isolated components and integration tests as checks that two or more components work together. Its ASP.NET Core guidance also notes that integration coverage can include databases, file systems, network appliances, and the request-response pipeline. See Microsoft’s integration-testing guidance.
Free tools Windows power users keep installed
One-click scans. No signup required.
Examples: what each test actually checks
Unit test: a deterministic validation rule
Suppose an application has a function that decides whether an email address is valid. Test it with fixed inputs and assert the returned result. Keep database and network behavior outside that test; replace any collaborators if necessary. This checks the rule itself, not whether the application can store a user or send a message.
function isValidEmail(value) {
return /^[^s@]+@[^s@]+.[^s@]+$/.test(value);
}
const cases = [
["[email protected]", true],
["missing-at.example.com", false],
];
for (const [input, expected] of cases) {
if (isValidEmail(input) !== expected) {
throw new Error(`Unexpected validation result for ${input}`);
}
}
This small JavaScript example can be saved as validate.js and run with node validate.js. It illustrates the unit-test boundary; it is not a claim that the example was executed as part of a test run. For a real project, use the test runner and conventions already used by that codebase.
Integration test: a request through the application
Start the application’s test host, send a request through its HTTP pipeline, and assert the response status and relevant content. This can cover routing, middleware, serialization, and application components working together. Microsoft’s ASP.NET Core example follows an arrange, act, assert pattern: prepare the test host and client, make a request, then check the response.
Integration test: a database round trip
Write a record through the application’s database configuration, read it back, and check that the data is correct. That boundary can expose failures in connection configuration, queries, mappings, or serialization that a unit test with a fake repository cannot reveal. Keep the test data isolated so the test can run reliably and clean up after itself.
Recommended Free Tools
Integration test: an external service boundary
Exercise the application’s API client against a local instance or a dedicated test instance when one is available, then verify how the application handles the response. Avoid sending automated test traffic to production. Fowler’s discussion of the practical test pyramid emphasizes testing real boundary behavior, while controlling the environment used for external collaborators.
Why teams use both layers
Unit tests are useful for checking lots of small rules quickly and pinpointing local logic errors. But when every collaborator is replaced, those tests cannot establish that the real components agree about request formats, configuration, or data. Integration tests exercise those seams and can catch interaction failures that isolated tests miss, at the cost of more setup and slower feedback.
Rank #4
Fowler notes that the term “integration test” is blurred: some teams use it for a focused external-collaborator check, while others mean a broader test across multiple modules. Two teams may therefore give different labels to similar tests. When communicating about coverage, state the boundary and environment—for example, “HTTP request through the test host with a real test database”—rather than treating the name as a complete specification. See Fowler’s discussion of integration-test terminology.
How to choose the right test layer
- Identify the behavior or failure risk. Be specific: a calculation is wrong, a route returns the wrong response, or a database write cannot be read back.
- Choose the narrowest layer that can answer the question. If either a unit or integration test would verify the behavior, Microsoft recommends the unit test in its .NET testing guidance.
- Use focused integration checks for important boundaries. Cover the interactions that matter—such as representative reads, writes, updates, and deletes—rather than testing every possible data permutation at the integration layer.
- Distribute coverage by risk and maintenance cost. Prioritize behavior according to the likelihood and impact of failure, and consider how expensive each layer is to maintain and run.
The test pyramid is a useful way to think about the trade-off: lower layers are generally more isolated and faster; broader, higher-level tests tend to be slower. It is a guide to balancing feedback and confidence, not a universal quota. The ISTQB Foundation Level syllabus discusses the model and its testing-layer trade-offs: Certified Tester Foundation Level Syllabus v4.0.1. The sources do not establish a fixed unit-to-integration test ratio.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesBest Value
Common mistakes and how to avoid them
- Choosing by test name alone: A test called “unit” may cover several components, and a test called “integration” may check one narrow boundary. Document the scope and which dependencies are real.
- Mocking the behavior the test is meant to verify: If the question is whether a database write works, a mocked database cannot answer it. Keep the mock for a unit-level question; use the intended database setup for the boundary check.
- Making integration tests too broad: A single test that depends on many services and lots of data can be difficult to diagnose. Prefer focused checks around high-value interactions.
- Testing every permutation at the slowest layer: Keep detailed input and branch coverage near the unit being tested; reserve integration coverage for representative boundary behavior.
- Using production services for automated runs: External systems can change, impose costs, or receive unintended test traffic. Prefer local or dedicated test instances where available.
A separate tool for capturing rendered pages
ScreenshotNeo is a website screenshot API and MCP server, not a unit-testing or integration-testing framework. It may be relevant when a separate workflow needs to capture a rendered page; a screenshot alone does not establish that application logic or component interactions passed a test. One GET request can return a PNG, JPEG, WebP, or PDF. The API accepts the parameter names used by other screenshot APIs, which can make switching easier.
For example, save the response for a rendered page as a WebP image with cURL. The API key is supplied by ScreenshotNeo; replace the target URL as needed. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
- Before capture, it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in
X-Page-VerdictandX-Billedheaders. - An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Yearly billing gives two months free, and every feature is available on every plan.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




