こまぶろ

技術のこととか仕事のこととか。

【Angular】HTTP通信のテストでのインジェクションのエラーの解消

Angular*1のHTTP通信部分(Serviceクラス)のテスト*2を書く際に、派手につまずいたので対応方法と経緯をメモ。

テスト対象の実装

HTTP通信には、AngularのHttpClientを用いている。

実装側のコードにおいては、公式ドキュメントにあるように、通信を使用するModuleクラス*3HttpClientModuleをインポートしたうえで、ServiceクラスにHttpClientをインジェクトする。これでHTTP通信が利用できるようになる。

これのテストコードを書きたい。公式ドキュメントには、モックを用いたテストの方法が書いてあるが、今回は実際のAPI(サーバーサイドの実装)をテストしたいという意味合いもあったので、モックを利用しないテストを書く。

対応方法

結論から先に書くと、テスト側のコードにおいては、下記のように、HttpClientModuleをインポートすればよい。

beforeEach(() => TestBed.configureTestingModule({
  imports: [HttpClientModule]
}));

以上のように記載することで、テスト実行時に正常にHTTP通信を実行することができる。

対応までの経緯

まず、何も考えずにテストケース(itの部分)を記載する。すると、下記のようなエラーになる。

Error: StaticInjectorError(DynamicTestModule)[ConnpassService -> HttpClient]: 
  StaticInjectorError(Platform: core)[ConnpassService -> HttpClient]: 
    NullInjectorError: No provider for HttpClient!

HttpClientのインジェクトに失敗したと言われる。確かに、実装側のServiceクラスは、HttpClientをインジェクトされている。そこで、下記のように書きたくなった。

  beforeEach(() => TestBed.configureTestingModule({
    providers: [HttpClient]
  }));

実行すると、下記のようなエラーとなる。

Error: StaticInjectorError(DynamicTestModule)[HttpClient -> HttpHandler]: 
  StaticInjectorError(Platform: core)[HttpClient -> HttpHandler]: 
    NullInjectorError: No provider for HttpHandler!

インジェクションに失敗しているらしい。「HttpHandlerがないと怒られているのかー」と考え、providersに追加してみる。

beforeEach(() => TestBed.configureTestingModule({
  providers: [HttpClient, HttpHandler]
}));

テストを再実行すると、下記のようなエラーになった。

Expected TypeError: _this.handler.handle is not a function to be null.

このエラーメッセージは苦しい。Googleで検索してもなかなかズバリ答えが見つけられなかった。

そもそも、HttpClientは明示的に実装側でインジェクトしているものなのに対して、HttpHandlerはそうではない。エラーメッセージを見て、何も考えずにprovidersに追加してしまったが、モックを利用しているわけでもないのに実装側で意識していないことをテスト側で意識しなければならないのはどこかがおかしいと思うべきだった。

試行錯誤を繰り返した結果、先述のようにimportsHttpClientModuleを記載したことでエラーが解消した。実装側で、

  • HttpClientModuleをインポート
  • HttpClientをインジェクト

という2段階を踏んでいるのだから、真っ先にHttpClientModuleへの依存を疑うべき事案だった。

感想

依存しているモジュールをimportsに追加するというのは、Angularの仕組み、TestBedクラスの仕組みを理解していればすぐにわかることなのだろう。有識者に聞けばすぐに答えが返ってくると思われるので、Angular Japan User GroupのSlackも活用していきたい。

今回、テストについての情報をGoogleを駆使して検索してみて、うまく答えにたどり着けなかった。エラーメッセージで検索をするのが常套手段だが、英語の記事を含めてあまり的確な情報を獲得することができなかったので、記事として書いておくことにした。

※記事の内容の誤り、もっといい対応方法等があれば、ぜひご指摘ください。

*1:Angularのバージョンは、7.0.4。

*2:Angular CLIで作成したプロジェクトにデフォルトで設定されるJasmine + Karmaによるテスト。

*3:AppModuleが一般的とドキュメントに記載されている。