An integration test checks whether code works with dependencies that are real rather than fully controlled in memory. It may use a real database, filesystem, network, REST API, system time, or configuration. The test exercises an entry point and observes a result, but it also depends on conditions outside the code being focused on. section 1.11 section 1.8
This differs from a unit test, where dependencies are in memory and their behavior is controlled. Integration tests provide useful confidence that code works with things it does not control, but that confidence costs speed, simplicity, and dependable results. A passing test checks multiple pieces working together; a failing test can leave many possible causes to investigate. section 1.11 section 10.1.3 section 1.8
Testing an asynchronous network call
Call an async function that checks a website, await its result, and assert that it reports success and an "ok" status. The test is concise, but still an integration test because the network call remains asynchronous and depends on external conditions. section 6.1.3
Expect practical trade-offs when real dependencies are involved:
- Runs more slowly; network, database, filesystem, or thread dependencies can add substantial time. section 1.8 section 10.1.3
- Can be flaky because timings, environments, configuration, and external services vary. section 6.1.4
- Makes negative scenarios harder to simulate, such as unavailable networks or incorrect remote content. section 6.1.4
- Can test irrelevant layers or dependencies, making failures longer to diagnose and easier to mistrust. section 6.1.4
Use integration tests as a complement to lower-level tests, not as a replacement for them. Keep their number limited enough to retain confidence, and separate them from fast, nonflaky unit tests. Run the fast set frequently; let an automated build pipeline run the broader feedback tests. section 6.1.4 section 7.4.3 section 10.5
Integration tests are also a practical starting point for legacy code. Before refactoring a hard-to-isolate system, capture its current behavior with tests that use the real system, change code in small steps, and run those tests often. Afterward, replace most with smaller unit tests where possible. section 12.3 section 12.4
Figure 1.7 You can have many failure points in an integration test. All the units have to work together, and each could malfunction, making it harder to find the source of a bug.
A failure can originate in any integrated unit or dependency, which explains why these tests often require broader investigation. section 1.8






























