Skip to content

Replacing HttpClientTestingModule in Angular Tests ​

Problem Statement ​

When migrating Angular tests to version 18.0.4+, you'll encounter a deprecation warning for HttpClientTestingModule:

txt
'HttpClientTestingModule' is deprecated. Add provideHttpClientTesting() to your providers instead.

Attempting to replace it by adding only provideHttpClientTesting() to providers results in a dependency error:

txt
NullInjectorError: No provider for _HttpClient!

This occurs because:

  1. HttpClientTestingModule handled both HTTP client provisioning and test environment setup
  2. The new function-based setup requires explicit separation of concerns
  3. Angular 18+ promotes standalone APIs and functional providers

Solution ​

The correct approach combines two provider functions:

typescript
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 actual HttpClient implementation for dependency injection
  • provideHttpClientTesting(): 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 ​

  1. provideHttpClientTesting() only sets up the test environment
  2. It doesn't provide the HttpClient service itself
  3. Without provideHttpClient(), dependencies needing HttpClient can't resolve

Migration Path

diff
TestBed.configureTestingModule({
-  imports: [HttpClientTestingModule],
+  providers: [
+    provideHttpClient(),
+    provideHttpClientTesting()
+  ]
})

Testing Best Practices ​

When working with HTTP tests in Angular 18+:

  1. Always import provideHttpClient() to satisfy service dependencies
  2. Use provideHttpClientTesting() to enable request mocking
  3. Inject HttpTestingController to manage mock expectations:
typescript
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);
});
  1. For services using HttpClient, provide them directly:
typescript
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.