We use HttpTestingController to check if our Angular app makes the right HTTP requests without actually calling a server.
Testing HTTP calls with HttpTestingController in Angular
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Angular
import { HttpTestingController, HttpClientTestingModule } from '@angular/common/http/testing'; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [YourService] }); httpTestingController = TestBed.inject(HttpTestingController); service = TestBed.inject(YourService); }); // In your test const req = httpTestingController.expectOne('url'); expect(req.request.method).toBe('GET'); req.flush(mockData); httpTestingController.verify();
Always import HttpClientTestingModule to use HttpTestingController.
Call httpTestingController.verify() to check no unexpected requests remain.
Examples
Angular
const req = httpTestingController.expectOne('api/data'); expect(req.request.method).toBe('GET'); req.flush({id: 1, name: 'Test'});
Angular
const req = httpTestingController.expectOne('api/save'); expect(req.request.method).toBe('POST'); req.flush({success: true});
Sample Program
This test checks that DataService.getData() sends a GET request to 'api/data' and receives the expected mock data.
Angular
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) {} getData() { return this.http.get<{id: number; name: string}>('api/data'); } } describe('DataService with HttpTestingController', () => { let service: DataService; let httpTestingController: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [DataService] }); service = TestBed.inject(DataService); httpTestingController = TestBed.inject(HttpTestingController); }); it('should fetch data with GET request', (done) => { const mockResponse = {id: 1, name: 'Test Item'}; service.getData().subscribe(data => { expect(data).toEqual(mockResponse); done(); }); const req = httpTestingController.expectOne('api/data'); expect(req.request.method).toBe('GET'); req.flush(mockResponse); httpTestingController.verify(); }); });
Important Notes
Use expectOne() to find a single HTTP request by URL.
Use flush() to simulate the server sending back data.
Always call verify() to ensure no unexpected HTTP calls remain after the test.
Summary
HttpTestingController helps test HTTP calls without real servers.
Use expectOne() to check requests and flush() to send mock responses.
Always verify no extra requests remain with verify().
Practice
1. What is the main purpose of
HttpTestingController in Angular testing?easy
Solution
Step 1: Understand HttpTestingController role
It is designed to intercept HTTP requests in tests and provide mock responses.Step 2: Differentiate from real HTTP calls
It does not send real requests but simulates them for testing purposes.Final Answer:
To mock and verify HTTP requests without calling a real server -> Option AQuick Check:
HttpTestingController mocks HTTP calls = B [OK]
Hint: HttpTestingController mocks HTTP calls, no real server needed [OK]
Common Mistakes:
- Thinking it sends real HTTP requests
- Confusing it with service mocking
- Assuming it logs requests automatically
2. Which of the following is the correct way to inject
HttpTestingController in an Angular test?easy
Solution
Step 1: Recall Angular TestBed injection syntax
Use TestBed.inject() to get service instances in tests.Step 2: Check each option
Only const httpMock = TestBed.inject(HttpTestingController); uses correct syntax: TestBed.inject(HttpTestingController).Final Answer:
const httpMock = TestBed.inject(HttpTestingController); -> Option DQuick Check:
Use TestBed.inject() for services in tests = D [OK]
Hint: Use TestBed.inject() to get HttpTestingController instance [OK]
Common Mistakes:
- Trying to instantiate HttpTestingController with new
- Using incorrect module methods
- Passing wrong parameters to inject
3. Given this test snippet, what will
req.request.method output?
const req = httpMock.expectOne('/api/data');
console.log(req.request.method);medium
Solution
Step 1: Understand expectOne returns a TestRequest
TestRequest has arequestproperty with HTTP method info.Step 2: The method reflects the actual HTTP call
If the tested service called GET on '/api/data',req.request.methodis 'GET'.Final Answer:
'GET' if the tested service made a GET request to '/api/data' -> Option AQuick Check:
req.request.method matches actual HTTP method = A [OK]
Hint: expectOne().request.method shows actual HTTP method used [OK]
Common Mistakes:
- Assuming method is always POST or PUT
- Thinking request property is undefined
- Confusing expectOne with expectNone
4. What is the likely cause of this error in an Angular HTTP test?
Error: Expected one matching request for criteria "Match URL: '/api/items'", found none.
medium
Solution
Step 1: Analyze the error message
It says no matching request was found for '/api/items'.Step 2: Understand expectOne behavior
expectOne throws if no request matches the URL, meaning no request was made.Final Answer:
The tested service did not make any HTTP request to '/api/items' -> Option BQuick Check:
No matching request means no HTTP call made = C [OK]
Hint: No matching request means tested code didn't call that URL [OK]
Common Mistakes:
- Assuming verify() missing causes this error
- Thinking injection failure causes this error
- Ignoring URL typos in expectOne
5. In a test, you want to verify that exactly one GET request to '/api/users' was made and respond with mock data. Which code snippet correctly does this using
HttpTestingController?hard
Solution
Step 1: Use expectOne to find the GET request
expectOne({method: 'GET', url: '/api/users'}) finds the single matching request.Step 2: Respond with mock data using flush
Calling req.flush with mock user array simulates a successful response.Step 3: Call verify to ensure no unexpected requests
httpMock.verify() confirms all requests were handled.Final Answer:
const req = httpMock.expectOne({method: 'GET', url: '/api/users'}); req.flush([{ id: 1, name: 'Alice' }]); httpMock.verify(); -> Option CQuick Check:
expectOne + flush + verify = A [OK]
Hint: Use expectOne, flush mock data, then verify no extra requests [OK]
Common Mistakes:
- Using expectNone instead of expectOne
- Calling error instead of flush for success
- Not calling verify after flush
