라떼군 이야기


Angular 18: HttpClientTestingModule Deprecated 경고 및 No provider for _HttpClient 에러 해결 방법

Problem

Angular 18 버전으로 애플리케이션을 업그레이드한 후 테스트 코드를 실행하면 'HttpClientTestingModule' is deprecated. Add provideHttpClientTesting() to your providers instead.라는 경고 메시지가 나타납니다. 가이드에 따라 providers 배열에 provideHttpClientTesting()을 추가하면, 이번에는 NullInjectorError: No provider for _HttpClient!라는 에러가 발생하며 테스트가 실패합니다. 개발자는 단순히 모듈을 함수로 교체했을 뿐인데 의존성 주입 에러가 발생하여 당황할 수 있습니다.

Background

Angular는 버전 15부터 Standalone Component API를 도입하며 기존의 NgModule 기반 설정에서 함수 기반의 Provider 설정으로 점진적인 전환을 진행하고 있습니다. 이에 따라 HTTP 클라이언트 설정 역시 HttpClientModule 대신 provideHttpClient()를 사용하는 방식으로 변경되었습니다. 테스트 환경에서도 마찬가지로 HttpClientTestingModule이 Deprecated 되었고, provideHttpClientTesting() 함수가 이를 대체하게 되었습니다. 하지만 중요한 차이점이 있습니다. 기존의 HttpClientTestingModule은 내부적으로 HttpClient 자체도 함께 제공했지만, 새로운 provideHttpClientTesting()은 오직 테스트를 위한 모킹(Mocking) 환경만 구성할 뿐 HttpClient 인스턴스를 제공하지 않습니다. 이로 인해 HttpClient를 주입받는 서비스나 컴포넌트에서 No provider 에러가 발생하는 것입니다.

Solution

이 문제를 해결하기 위해서는 provideHttpClient()provideHttpClientTesting()을 함께 선언해야 합니다. provideHttpClient()가 실제 HttpClient를 주입할 수 있게 해주고, provideHttpClientTesting()이 테스트 환경에 맞게 HTTP 백엔드를 모킹해 줍니다.

올바른 Provider 설정 방법

import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { AssetDetailsComponent } from './asset-details.component';

describe('AssetDetailsComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        // Standalone 컴포넌트 임포트
        AssetDetailsComponent,
      ],
      providers: [
        // 1. HttpClient를 의존성 주입 시스템에 등록합니다.
        provideHttpClient(),
        
        // 2. 테스트 환경을 위한 Mock 백엔드(HttpTestingController 등)를 구성합니다.
        // 반드시 provideHttpClient()와 함께 선언해야 합니다.
        provideHttpClientTesting(),
      ]
    }).compileComponents();
  });

  it('should create', () => {
    const fixture = TestBed.createComponent(AssetDetailsComponent);
    const component = fixture.componentInstance;
    expect(component).toBeTruthy();
  });
});

이렇게 두 함수를 함께 사용하면 기존 HttpClientTestingModule이 하던 역할을 완벽하게 대체할 수 있습니다. 만약 provideHttpClient()만 단독으로 사용한다면 에러는 사라지지만, 실제 HTTP 요청이 네트워크를 타고 나가버리는 문제가 발생하므로 테스트 환경에서는 반드시 두 함수를 함께 사용해야 합니다.

Deep Dive

테스트 환경이 올바르게 구성되었다면 HttpTestingController를 주입받아 API 요청을 가로채고(mock) 응답을 검증할 수 있습니다. 테스트가 끝난 후에는 afterEach 훅에서 HttpTestingController.verify()를 호출하여 예상치 못한 추가 HTTP 요청이 발생하지 않았는지 검증하는 것이 베스트 프랙티스입니다. 또한, Angular 최신 버전의 함수형 Provider 패턴은 트리 쉐이킹(Tree-shaking)을 최적화하여 테스트 번들 크기를 줄이고 실행 속도를 향상시키는 데 기여합니다.

Conclusion

Angular 18에서 HttpClientTestingModule이 Deprecated 됨에 따라 테스트 코드를 마이그레이션할 때는 provideHttpClient()provideHttpClientTesting()을 함께 providers 배열에 추가해야 합니다. 이를 통해 의존성 주입 에러를 해결하고, 실제 네트워크 요청 없이 안전하고 격리된 HTTP 테스트 환경을 구축할 수 있습니다.

References

프리랜서로 제품 기획과 개발을 맡길 파트너가 필요하신가요? 개인, 팀, 기업 누구나 의뢰할 수 있으며 문제 정의부터 출시까지 함께합니다.