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

  1. What is HTTP Testing?
  2. Why HTTP Testing?
  3. Angular HTTP Testing Architecture
  4. provideHttpClientTesting()
  5. HttpTestingController
  6. Testing GET Requests
  7. Testing POST Requests
  8. Testing PUT Requests
  9. Testing DELETE Requests
  10. Testing Error Responses
  11. Testing HTTP Interceptors
  12. Async HTTP Testing
  13. Enterprise Banking Example
  14. Best Practices
  15. Common Mistakes
  16. Top 10 Interview Questions
  17. Interview Cheat Sheet
  18. 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.
  • HttpTestingController intercepts 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