Replacing HttpClientTestingModule in Angular Tests
Problem Statement
When migrating Angular tests to version 18.0.4+, you'll encounter a deprecation warning for HttpClientTestingModule
:
'HttpClientTestingModule' is deprecated. Add provideHttpClientTesting() to your providers instead.
Attempting to replace it by adding only provideHttpClientTesting()
to providers results in a dependency error:
NullInjectorError: No provider for _HttpClient!
This occurs because:
HttpClientTestingModule
handled both HTTP client provisioning and test environment setup- The new function-based setup requires explicit separation of concerns
- Angular 18+ promotes standalone APIs and functional providers
Solution
The correct approach combines two provider functions:
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
await TestBed.configureTestingModule({
imports: [
AssetDetailsComponent, // Your component under test
],
providers: [
provideHttpClient(), // Provides the base HTTP client
provideHttpClientTesting() // Configures testing environment
]
}).compileComponents();
Key Points
provideHttpClient()
: Supplies the actualHttpClient
implementation for dependency injectionprovideHttpClientTesting()
: Configures mock backend and interceptors for testing- Order doesn't matter - Angular DI handles both regardless of sequence
- This pattern matches Angular's new functional module philosophy
Why Previous Solution Failed
provideHttpClientTesting()
only sets up the test environment- It doesn't provide the
HttpClient
service itself - Without
provideHttpClient()
, dependencies needingHttpClient
can't resolve
Migration Path
TestBed.configureTestingModule({
- imports: [HttpClientTestingModule],
+ providers: [
+ provideHttpClient(),
+ provideHttpClientTesting()
+ ]
})
Testing Best Practices
When working with HTTP tests in Angular 18+:
- Always import
provideHttpClient()
to satisfy service dependencies - Use
provideHttpClientTesting()
to enable request mocking - Inject
HttpTestingController
to manage mock expectations:
import { HttpTestingController } from '@angular/common/http/testing';
let httpTestingController: HttpTestingController;
beforeEach(() => {
httpTestingController = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpTestingController.verify(); // Verify no pending requests
});
it('should fetch data', () => {
// Test implementation here
const req = httpTestingController.expectOne('/api/data');
req.flush(mockData);
});
- For services using HttpClient, provide them directly:
TestBed.configureTestingModule({
providers: [
DataService, // Your service using HttpClient
provideHttpClient(),
provideHttpClientTesting()
]
});
Additional Considerations
- For application testing (not unit tests), continue using
provideHttpClient(withFetch())
- Always verify HTTP requests in
afterEach
to prevent test leakage - Use
HttpClientTestingModule
only in Angular 17 or earlier - The migration pattern is consistent across components, services, and interceptors
Hybrid Migration
During migration projects with mixed modules and standalone components:
- Functional providers work in both module-based and standalone environments
- Avoid mixing functional providers with
imports:[HttpClientTestingModule]
For comprehensive examples, refer to Angular's HTTP Testing Documentation.