Angular HTTP Testing
Learn Angular HTTP Testing with HttpTestingController, provideHttpClientTesting(), request matching, mock responses, error testing, interceptors, async testing, enterprise best practices, and interview questions.
Modern Angular applications communicate with backend APIs for:
- Authentication
- Customer Management
- Payments
- Orders
- Notifications
- Reports
Testing these HTTP interactions is critical.
Calling real APIs during unit testing makes tests:
- Slow
- Unreliable
- Dependent on external systems
Angular provides HttpTestingController and provideHttpClientTesting() to simulate HTTP requests without contacting a real server.
Table of Contents
- What is HTTP Testing?
- Why HTTP Testing?
- Angular HTTP Testing Architecture
- provideHttpClientTesting()
- HttpTestingController
- Testing GET Requests
- Testing POST Requests
- Testing PUT Requests
- Testing DELETE Requests
- Testing Error Responses
- Testing HTTP Interceptors
- Async HTTP Testing
- Enterprise Banking Example
- Best Practices
- Common Mistakes
- Top 10 Interview Questions
- Interview Cheat Sheet
- Summary
What is HTTP Testing?
HTTP Testing verifies that Angular services correctly:
- Send requests
- Receive responses
- Handle errors
- Process data
- Retry requests
- Add headers
- Communicate with APIs
Instead of making actual network calls, Angular returns mock responses.
Why HTTP Testing?
Benefits include:
- Fast execution
- Reliable tests
- No network dependency
- Repeatable results
- Easy error simulation
- Better code quality
Angular HTTP Testing Architecture
flowchart LR
TestCase
TestCase --> CustomerService
CustomerService --> HttpClient
HttpClient --> HttpTestingController
HttpTestingController --> MockResponse
MockResponse --> Assertions
Required Testing Providers
Angular 17+ uses provider-based configuration.
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
CustomerService
]
});
});
HttpTestingController
Inject the testing controller.
let httpMock: HttpTestingController;
beforeEach(() => {
httpMock = TestBed.inject(
HttpTestingController
);
});
Responsibilities:
- Intercept requests
- Return mock responses
- Verify requests
- Simulate errors
Testing Flow
flowchart LR
Service
Service --> HttpClient
HttpClient --> HttpTestingController
HttpTestingController --> MockResponse
MockResponse --> Subscriber
Subscriber --> Assertions
Sample Service
@Injectable({
providedIn: 'root'
})
export class CustomerService {
constructor(
private http: HttpClient
) {}
getCustomers() {
return this.http.get<Customer[]>(
'/api/customers'
);
}
}
Testing GET Requests
it('should load customers', () => {
service.getCustomers()
.subscribe(customers => {
expect(customers.length)
.toBe(2);
});
const request =
httpMock.expectOne(
'/api/customers'
);
expect(request.request.method)
.toBe('GET');
request.flush([
{
id: 1,
name: 'John'
},
{
id: 2,
name: 'Jane'
}
]);
});
Testing POST Requests
Service
createCustomer(customer: Customer) {
return this.http.post(
'/api/customers',
customer
);
}
Test
service.createCustomer(customer)
.subscribe();
const request =
httpMock.expectOne(
'/api/customers'
);
expect(request.request.method)
.toBe('POST');
expect(request.request.body)
.toEqual(customer);
request.flush(customer);
Testing PUT Requests
service.updateCustomer(customer)
.subscribe();
const request =
httpMock.expectOne(
'/api/customers/1'
);
expect(request.request.method)
.toBe('PUT');
request.flush(customer);
Testing DELETE Requests
service.deleteCustomer(1)
.subscribe();
const request =
httpMock.expectOne(
'/api/customers/1'
);
expect(request.request.method)
.toBe('DELETE');
request.flush({});
HTTP Request Lifecycle
sequenceDiagram
participant Test
participant Service
participant HttpTestingController
Test->>Service: Call Method
Service->>HttpTestingController: HTTP Request
HttpTestingController-->>Service: Mock Response
Service-->>Test: Observable Result
Matching Requests
Exact URL
httpMock.expectOne(
'/api/customers'
);
Predicate
httpMock.expectOne(
request =>
request.method === 'GET'
);
Multiple Requests
const requests =
httpMock.match(
'/api/customers'
);
Testing Error Responses
Example
service.getCustomers()
.subscribe({
error: error => {
expect(error.status)
.toBe(500);
}
});
const request =
httpMock.expectOne(
'/api/customers'
);
request.flush(
'Server Error',
{
status:500,
statusText:'Internal Server Error'
}
);
Always test failure scenarios as well as successful responses.
Testing Network Errors
const request =
httpMock.expectOne(
'/api/customers'
);
request.error(
new ProgressEvent(
'network error'
)
);
Useful for:
- Lost internet
- Timeout simulation
- Connection failures
Testing Headers
expect(
request.request.headers.get(
'Authorization'
)
)
.toContain('Bearer');
Common headers
- Authorization
- Content-Type
- Accept
- X-Request-ID
- X-Correlation-ID
Testing Query Parameters
expect(
request.request.params.get(
'page'
)
)
.toBe('1');
Example URL
/api/customers?page=1&size=20
Testing HTTP Interceptors
Verify that interceptors modify requests correctly.
Example
expect(
request.request.headers.has(
'Authorization'
)
)
.toBeTrue();
Typical interceptor behavior
- JWT token
- Correlation ID
- Logging
- Retry
- Error handling
Verifying Outstanding Requests
afterEach(() => {
httpMock.verify();
});
verify() ensures that every expected request has been handled and that no unexpected requests remain.
Async HTTP Testing
Observable example
it('loads data',
async () => {
const customers =
await firstValueFrom(
service.getCustomers()
);
expect(customers)
.toHaveLength(2);
});
Other options
- fakeAsync()
- tick()
- waitForAsync()
Enterprise Banking Example
Services
- Login API
- Accounts API
- Payment API
- Transaction API
- Loan API
- Notification API
Testing Strategy
| API | Test Focus |
|---|---|
| Login | Authentication |
| Accounts | GET Requests |
| Payments | POST Requests |
| Transactions | Query Parameters |
| Loans | Error Handling |
| Notifications | Retry Logic |
Enterprise Testing Flow
flowchart TD
Developer
Developer --> ServiceTest
ServiceTest --> HttpTestingController
HttpTestingController --> MockBackend
MockBackend --> Assertions
Assertions --> CI
Performance Best Practices
| Practice | Benefit |
|---|---|
| Mock Every HTTP Call | Faster tests |
| Verify Request Method | Correct behavior |
| Verify Headers | Secure APIs |
| Test Query Parameters | Correct requests |
| Test Errors | Better reliability |
| Test Network Failures | Resilient applications |
| Call verify() | Complete validation |
| Run in CI/CD | Continuous quality |
Common Mistakes
Calling Real APIs
Never use production APIs during unit testing.
Always mock HTTP requests.
Forgetting verify()
Always include
afterEach(() => {
httpMock.verify();
});
This prevents unnoticed pending requests.
Testing Only Success Responses
Also verify:
- 400 Bad Request
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 500 Internal Server Error
- Network failures
Ignoring Request Body
Always validate:
request.request.body
for POST and PUT requests.
Ignoring Headers
Verify authentication and custom headers when they are required.
HTTP Testing Best Practices
| Practice | Recommendation |
|---|---|
| Mock All Requests | Always |
| Verify HTTP Method | Yes |
| Verify URL | Yes |
| Verify Headers | Yes |
| Verify Request Body | Yes |
| Test Error Cases | Yes |
| Call verify() | Always |
| Automate in CI/CD | Yes |
HttpTestingController vs Real Backend
| Feature | HttpTestingController | Real Backend |
|---|---|---|
| Network Call | ❌ | ✅ |
| Speed | Very Fast | Slower |
| Deterministic | ✅ | Depends on server |
| Error Simulation | Easy | Difficult |
| Unit Testing | ✅ | ❌ |
| Integration Testing | ❌ | ✅ |
Advantages
| Benefit | Description |
|---|---|
| Fast Execution | No real network |
| Reliable Tests | Deterministic responses |
| Easy Error Simulation | Test edge cases |
| Complete Request Validation | URL, headers, body |
| Enterprise Ready | CI/CD friendly |
| Better Code Quality | High confidence |
Top 10 HTTP Testing Interview Questions
1. What is Angular HTTP Testing?
Answer
HTTP Testing verifies that Angular services send the correct HTTP requests, process responses correctly, and handle errors without contacting a real backend.
2. What is HttpTestingController?
Answer
HttpTestingController intercepts HTTP requests during testing and allows developers to return mock responses and verify request details.
3. Why use provideHttpClientTesting()?
Answer
provideHttpClientTesting() configures Angular to use testing utilities for HttpClient, replacing real HTTP communication with mocked behavior.
4. How do you test a GET request?
Answer
Call the service method, use expectOne() to capture the request, verify the request, and return mock data using flush().
5. What does flush() do?
Answer
flush() provides a mock response to the intercepted HTTP request, allowing the Observable to complete with test data.
6. Why call verify()?
Answer
verify() ensures that all expected HTTP requests have been handled and no unexpected requests remain.
7. How do you test HTTP errors?
Answer
Use flush() with an error status or request.error() to simulate server or network failures and verify the service's error handling.
8. Can you verify request headers?
Answer
Yes. Use request.request.headers to verify headers such as Authorization, Content-Type, or custom headers.
9. How do you test query parameters?
Answer
Inspect request.request.params and verify that expected query parameter values are present.
10. What are HTTP Testing best practices?
Answer
- Mock all HTTP requests
- Verify URL and HTTP method
- Verify request headers and body
- Test success and error scenarios
- Call
verify() - Keep tests independent
- Automate execution in CI/CD
Interview Cheat Sheet
| Requirement | Recommended Tool |
|---|---|
| HTTP Mocking | HttpTestingController |
| HttpClient Testing | provideHttpClientTesting() |
| GET Testing | expectOne() + flush() |
| POST Testing | Verify Body |
| Error Testing | flush() / request.error() |
| Header Validation | request.headers |
| Query Parameters | request.params |
| Outstanding Requests | verify() |
| Async Testing | firstValueFrom() |
| Enterprise Testing | Mock Every HTTP Call |
Summary
Angular HTTP Testing enables developers to verify API communication without relying on external servers. Using provideHttpClientTesting() and HttpTestingController, teams can validate request URLs, methods, headers, query parameters, request bodies, successful responses, and error scenarios in a fast and deterministic environment. A comprehensive HTTP testing strategy improves reliability, prevents regressions, and supports enterprise-grade continuous integration and deployment workflows.
Key Takeaways
- ✅ Use
provideHttpClientTesting()to configure HTTP testing. - ✅
HttpTestingControllerintercepts and mocks HTTP requests. - ✅ Verify request URLs, methods, headers, parameters, and bodies.
- ✅ Use
flush()to return mock responses. - ✅ Test both successful and failure scenarios.
- ✅ Simulate network failures with
request.error(). - ✅ Always call
httpMock.verify(). - ✅ Mock every external HTTP dependency.
- ✅ Automate HTTP tests in CI/CD pipelines.
- ✅ HTTP Testing is one of the most common Angular interview topics.
Next Article
➡️ 116-Mocking-and-Spies-QA.md