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.