How do you mock an async service call in an Angular component test?

This tests Angular unit isolation and HTTP mocking. A strong answer covers HttpTestingController setup, flushing a mock response, asserting UI changes, and notes mocking avoids flaky networks. Red flag: using real HTTP calls in unit tests.
WHAT THIS TESTS: This question evaluates whether you understand test isolation and deterministic control over asynchronous dependencies in Angular. The interviewer cares if you know how to decouple a component from real network behavior and whether you grasp the difference between shallow unit tests and full integration tests. They also want to see that you understand how Angular's testing utilities replace the real HTTP backend with a controllable test harness.
A GOOD ANSWER COVERS: First, the candidate should mention two valid strategies. The first strategy is to override the injected service in TestBed providers with a fake stub object that returns a cold Observable or Promise. The second strategy is to keep the real service but replace the HTTP backend by importing provideHttpClientTesting and using HttpTestingController to intercept outgoing calls. Second, the candidate should walk through the flush pattern in order: trigger the component action that initiates the request, use httpTesting.expectOne to capture the pending request and assert its method or URL, call req.flush with a mock payload to synchronously complete the response, and then assert that the component state or template updates correctly. Third, the candidate should explain why mocking is crucial: it eliminates flaky network latency, prevents tests from failing when the backend is unavailable, allows simulation of error conditions like timeouts or 500 responses, and keeps test execution fast. Fourth, a complete answer mentions calling httpTesting.verify at the end of the test to ensure no unexpected requests were made.
COMMON WRONG ANSWERS: One red flag is suggesting that component unit tests should make real HTTP calls to a live server. Another is manually managing asynchronous timing with setTimeout or JavaScript done callbacks instead of leveraging Angular's fakeAsync or waitForAsync test utilities. Some candidates forget to call flush which leaves Observables hanging and causes the test to fail with timeouts. Others call verify before the request has actually been issued, or they provide the real HttpClient without provideHttpClientTesting and then wonder why network calls leak out.
LIKELY FOLLOW-UPS: The interviewer may ask how you would simulate an error response, which you do by calling req.flush with an error payload and an explicit status code such as 404 or 500. They might ask how to handle tests that fire multiple requests, where you use expectOne for each distinct endpoint or use match to handle dynamic query parameters. Another common follow-up is how you test a service method that returns an Observable which emits multiple values over time, or how you would structure tests when the component uses signals that react to the HTTP response.
ONE CONCRETE EXAMPLE: Imagine a ProfileComponent that calls ProfileService.loadProfile which internally performs an HTTP GET to api/profile. In the test module setup you include provideHttpClient followed by provideHttpClientTesting. You inject HttpTestingController, trigger the component lifecycle, then capture the pending request using httpTesting.expectOne with the URL api/profile. You assert that req.request.method equals GET, then call req.flush with a mock profile object. After flushing, you assert that the component property bound to the template now contains the mock data and that the view renders the expected text. You finish with httpTesting.verify to confirm no additional requests escaped the test.
Source: angular.dev
Read the original → angular.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.