Bird
Raised Fist0
Angularframework~10 mins

Testing HTTP calls with HttpTestingController in Angular - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Testing HTTP calls with HttpTestingController
Test Setup
Make HTTP call in service
HttpTestingController intercepts call
Expect request with expectOne()
Flush mock response
Verify no outstanding requests
Test assertions on response
The test sets up HttpTestingController to catch HTTP calls, expects a request, sends a mock response, then verifies and asserts results.
Execution Sample
Angular
service.getData().subscribe(data => result = data);
const req = httpTestingController.expectOne('/api/data');
req.flush({id: 1, name: 'Test'});
httpTestingController.verify();
This code tests a service HTTP GET call by expecting the request, sending a fake response, and verifying no extra calls.
Execution Table
StepActionHttpTestingController StateRequest CapturedResponse SentTest State
1Call service.getData()No requests yetNoNoSubscription waiting
2expectOne('/api/data') calledOne request pendingYes, to /api/dataNoSubscription waiting
3req.flush({id:1, name:'Test'})Request fulfilledYesYes, with mock dataSubscription receives data
4httpTestingController.verify()No outstanding requestsNoYesTest ready for assertions
5Assertions run on resultNo requestsNoYesTest passes if data matches
💡 All expected HTTP requests handled and verified, test completes successfully
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3After Step 4Final
resultundefinedundefinedundefined{id:1, name:'Test'}{id:1, name:'Test'}{id:1, name:'Test'}
httpTestingController.requests[][GET /api/data][GET /api/data][][][]
Key Moments - 3 Insights
Why do we need to call expectOne() after making the HTTP call?
expectOne() tells HttpTestingController to look for a specific HTTP request. Without it, the test won't know which request to mock or verify, as shown in step 2 of the execution_table.
What happens if we forget to call httpTestingController.verify()?
If verify() is not called, the test might miss detecting unhandled HTTP requests, causing false positives. Step 4 shows verify() clears outstanding requests to ensure test completeness.
Why do we use req.flush() in the test?
req.flush() sends a fake response to the HTTP call so the subscription can receive data and continue. Step 3 shows how flush triggers the response delivery.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the state of 'result' after step 3?
A{id:1, name:'Test'}
Bundefined
Cnull
DAn error
💡 Hint
Check the variable_tracker row for 'result' after Step 3
At which step does HttpTestingController confirm no outstanding requests?
AStep 3
BStep 4
CStep 2
DStep 5
💡 Hint
Look at the 'HttpTestingController State' column in execution_table
If we skip calling req.flush(), what happens to the subscription?
AIt receives the mock data anyway
BIt throws an error immediately
CIt never receives data and stays waiting
DThe test fails at expectOne()
💡 Hint
Refer to step 3 in execution_table where flush sends the response
Concept Snapshot
Testing HTTP calls with HttpTestingController:
- Use HttpTestingController to intercept HTTP calls in tests.
- Call expectOne() to find the request.
- Use req.flush() to send mock response.
- Call verify() to ensure no unexpected requests.
- Assert results after flush delivers data.
Full Transcript
This visual execution shows how Angular's HttpTestingController helps test HTTP calls. First, the service method triggers an HTTP request. HttpTestingController catches it, and expectOne() confirms the request was made. Then, req.flush() sends a fake response so the subscription receives data. Finally, verify() checks no other requests remain. Variables like 'result' update after flush. This step-by-step trace helps beginners see how HTTP testing works in Angular.

Practice

(1/5)
1. What is the main purpose of HttpTestingController in Angular testing?
easy
A. To mock and verify HTTP requests without calling a real server
B. To create real HTTP requests to test backend APIs
C. To replace Angular services with fake implementations
D. To automatically generate HTTP request logs during tests

Solution

  1. Step 1: Understand HttpTestingController role

    It is designed to intercept HTTP requests in tests and provide mock responses.
  2. Step 2: Differentiate from real HTTP calls

    It does not send real requests but simulates them for testing purposes.
  3. Final Answer:

    To mock and verify HTTP requests without calling a real server -> Option A
  4. Quick 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
A. const httpMock = inject(HttpTestingController, TestBed);
B. const httpMock = new HttpTestingController();
C. const httpMock = HttpClientTestingModule.get(HttpTestingController);
D. const httpMock = TestBed.inject(HttpTestingController);

Solution

  1. Step 1: Recall Angular TestBed injection syntax

    Use TestBed.inject() to get service instances in tests.
  2. Step 2: Check each option

    Only const httpMock = TestBed.inject(HttpTestingController); uses correct syntax: TestBed.inject(HttpTestingController).
  3. Final Answer:

    const httpMock = TestBed.inject(HttpTestingController); -> Option D
  4. Quick 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
A. 'GET' if the tested service made a GET request to '/api/data'
B. 'POST' regardless of the actual request method
C. Throws an error because request is undefined
D. 'PUT' if the tested service made a PUT request to '/api/data'

Solution

  1. Step 1: Understand expectOne returns a TestRequest

    TestRequest has a request property with HTTP method info.
  2. Step 2: The method reflects the actual HTTP call

    If the tested service called GET on '/api/data', req.request.method is 'GET'.
  3. Final Answer:

    'GET' if the tested service made a GET request to '/api/data' -> Option A
  4. Quick 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
A. The test forgot to call httpMock.verify()
B. The tested service did not make any HTTP request to '/api/items'
C. HttpTestingController was not injected properly
D. The URL in expectOne has a typo but the request was made correctly

Solution

  1. Step 1: Analyze the error message

    It says no matching request was found for '/api/items'.
  2. Step 2: Understand expectOne behavior

    expectOne throws if no request matches the URL, meaning no request was made.
  3. Final Answer:

    The tested service did not make any HTTP request to '/api/items' -> Option B
  4. Quick 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
A. const req = httpMock.expectOne('/api/users'); req.error(new ErrorEvent('Network error')); httpMock.verify();
B. httpMock.expectNone('/api/users'); httpMock.verify();
C. const req = httpMock.expectOne({method: 'GET', url: '/api/users'}); req.flush([{ id: 1, name: 'Alice' }]); httpMock.verify();
D. const req = httpMock.expectOne('/api/users'); req.flush('');

Solution

  1. Step 1: Use expectOne to find the GET request

    expectOne({method: 'GET', url: '/api/users'}) finds the single matching request.
  2. Step 2: Respond with mock data using flush

    Calling req.flush with mock user array simulates a successful response.
  3. Step 3: Call verify to ensure no unexpected requests

    httpMock.verify() confirms all requests were handled.
  4. Final Answer:

    const req = httpMock.expectOne({method: 'GET', url: '/api/users'}); req.flush([{ id: 1, name: 'Alice' }]); httpMock.verify(); -> Option C
  5. Quick 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