How to Test HTTP Calls in Angular: Simple Guide
To test
HTTP calls in Angular, use HttpClientTestingModule to replace real HTTP requests with mocks, and HttpTestingController to control and assert requests. This lets you verify the request method, URL, and response without calling a real server.Syntax
Use HttpClientTestingModule in your test module imports to mock HTTP requests. Inject HttpTestingController to control and verify HTTP calls. Use expectOne() to find a request and flush() to provide a mock response.
HttpClientTestingModule: Replaces real HTTP with mocks.HttpTestingController: Lets you inspect and respond to requests.expectOne(url): Finds the HTTP request by URL.flush(data): Sends mock data as the response.
typescript
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { HttpClient } from '@angular/common/http'; TestBed.configureTestingModule({ imports: [HttpClientTestingModule] }); const httpClient = TestBed.inject(HttpClient); const httpTestingController = TestBed.inject(HttpTestingController); // Make HTTP call httpClient.get('/api/data').subscribe(response => { // handle response }); // Expect one request to /api/data const req = httpTestingController.expectOne('/api/data'); expect(req.request.method).toBe('GET'); // Respond with mock data req.flush({ key: 'value' }); // Verify no outstanding requests httpTestingController.verify();
Example
This example shows a simple Angular service test that mocks an HTTP GET call and verifies the response.
typescript
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() class DataService { constructor(private http: HttpClient) {} fetchData() { return this.http.get<{ message: string }>('/api/message'); } } describe('DataService HTTP Test', () => { let service: DataService; let httpTestingController: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [DataService] }); service = TestBed.inject(DataService); httpTestingController = TestBed.inject(HttpTestingController); }); it('should fetch message from API', () => { const mockResponse = { message: 'Hello Angular' }; service.fetchData().subscribe(data => { expect(data.message).toBe('Hello Angular'); }); const req = httpTestingController.expectOne('/api/message'); expect(req.request.method).toBe('GET'); req.flush(mockResponse); httpTestingController.verify(); }); });
Output
PASS DataService HTTP Test
✓ should fetch message from API
Common Pitfalls
- Not importing
HttpClientTestingModulecauses real HTTP calls, breaking tests. - Forgetting to call
httpTestingController.verify()leaves unresolved requests, causing test failures. - Using
expectOne()with wrong URL or multiple requests leads to errors. - Not flushing a response leaves the observable hanging.
typescript
/* Wrong: Missing HttpClientTestingModule import */ TestBed.configureTestingModule({ providers: [DataService] }); /* Right: Include HttpClientTestingModule */ TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [DataService] });
Quick Reference
- Import
HttpClientTestingModulein your test module. - Inject
HttpTestingControllerto control HTTP requests. - Use
expectOne(url)to find requests. - Call
flush(data)to send mock responses. - Always call
verify()to ensure no pending requests.
Key Takeaways
Always import HttpClientTestingModule to mock HTTP calls in Angular tests.
Use HttpTestingController to find and respond to HTTP requests.
Call expectOne() with the correct URL to target specific requests.
Flush mock data to simulate server responses and keep tests fast.
Verify no outstanding requests with httpTestingController.verify() after each test.