In this lesson, you will learn how to validate the communication between your internal services by replacing volatile remote dependencies with persistent, predictable test doubles.
The Challenge of Distributed Dependencies
In a microservices architecture, your Node.js application rarely operates in isolation. When your service needs to fetch data from an internal API, a real network call introduces non-determinism: the remote service might be down, slow, or returning unexpected state. Mocking these at the unit level is helpful, but integration testing across HTTP boundaries requires a higher level of fidelity—you need a "test double" that acts like a real HTTP server while remaining entirely under your control.
Using Persistent Test Doubles
Instead of mocking the internal fetch or axios module, we use persistent test doubles (like nock or a dedicated local HTTP server) to intercept requests at the network layer. This ensures your code's HTTP client configuration, headers, and serialization logic are actually exercised.
Consider an order service that fetches user details from an authentication service:
const nock = require('nock');
describe('Order Service Integration', () => {
beforeAll(() => {
// Define a persistent double for the internal service
nock('http://auth-service.internal')
.get('/users/123')
.reply(200, { id: 123, role: 'premium' });
});
it('correctly processes order for premium users', async () => {
const response = await request(app).post('/orders').send({ userId: 123 });
expect(response.status).toBe(201);
expect(response.body.discountApplied).toBe(true);
});
});
By defining these boundaries, you aren't just testing your business logic; you are validating that your service correctly interprets the HTTP contract of its dependencies. If the Auth service updates its API schema, your test suite will fail during the integration phase because the nock interceptor will no longer match the requests your service is sending. This keeps your communication logic strictly synchronized without requiring the entire infrastructure to be running during local development.
Key Takeaway: By using persistent HTTP test doubles, you transform unreliable network dependencies into deterministic integration points, ensuring your services communicate correctly without the fragility of real-world latency or downtime.