📦

VSCode Dev Containers上でTestcontainersを使う方法

 
こんにちは。Nstockのエンジニアの ryan5500 です。
今回は私たちの開発環境であるVSCode Dev Containers上で、Testcontainers (Java版) を利用する方法をご紹介します。

忙しい方向けの要点

Testcontainers (Java版)をVSCode Dev Containers上から利用する場合は、docker compose設定ファイルに以下の設定を追加する
  • Testcontainersがコンテナ起動の指示を出すため
    • を追加する
  • テスト時に開発用コンテナ内からTestcontainersが起動したコンテナに接続するため
    • を追加する
    • を追加する
 

前提: Nstockの開発環境

Nstockでは、M1 Mac上でVSCodeのDev Containersを利用して、開発に必要なツールを含めたコンテナで開発しています。具体的には、を用いて、開発用のコンテナとデータベースコンテナを立ち上げるようにしています。
 
ウェブサービスの開発には、以下の技術スタックを利用しています。
  • フロントエンド: TypeScript + Next.js
  • バックエンド: Java 17 + Spring Boot 2系
    • テスト関連ライブラリ: JUnit5系 + DBRider
  • バッチや運用ツール: Golang
  • データベース: PostgreSQL
 
チーム体制としては、開発の初期から3名のエンジニアがおり、それぞれ専門性が異なっていました。フロー効率を上げるため、各自が専門の特定領域のみ開発するよりは、フルスタックにやっていきたいと考えました。
 
フルスタックに開発していくにあたり、以下のようなニーズが生まれたため、現時点では共通の開発環境を利用しています。
  • 環境構築のコストを減らし開発に集中したい
  • 環境起因の問題のデバッグ時間を減らしたい
  • 各言語用の拡張機能を、専門性のある方に設定してもらいたい

バックエンドの統合テストにおけるデータベースアクセスの検討

バックエンドの統合テストを書く場合に、テストにおけるデータベースへのアクセスをどうするかを考える必要があり、以下のような選択肢がありそうでした。
  • テスト時のみin-memoryデータベースを利用する
  • VSCode Dev Containersで起動しているデータベースコンテナ内にテスト用のデータベースを用意し、テスト時にはそのデータベースを利用する
  • テスト用に別途データベースコンテナを用意する
 
PostgreSQLにおけるRoleごとのポリシー設定など、データベースの種類に依存した安全策を講じている背景から、できるだけ本番に近い環境を用意したいと考えました。
調査を進める中で、以下のメリットから、テスト用に様々なコンテナを起動できるTestcontainersを採用しました。
  • 本番と同じバージョンを指定してデータベースを利用できる
  • テストケースごとにデータベースコンテナを用意できるので、テストを並列実行する際にデータベースの取り合いにならず効果を発揮しそう
  • 将来的にデータベース以外にもジョブキュー等でコンテナを利用する可能性があるので、投資する価値がありそう

Testcontainersとは

Testcontainersは、Dockerコンテナを使用してアプリケーションの統合テストを実行するためのツールです。JavaだけでなくGolangやNode.jsなど、複数の言語で利用できるようになっています。
動作の仕組みとしては、公式サイトにある図がわかりやすいです。
https://testcontainers.com/getting-started/ より
https://testcontainers.com/getting-started/ より
 
これを我々のテストの文脈に読み替えると、以下のようになります。
  1. テストの実施前に、Testcontainersを呼び出して、テスト用のデータベースコンテナを起動させます。
  1. テストを実行します。ここで1点注意が必要で、テスト実行前に、データベースの接続情報を、Testcontainersが起動したコンテナに向けるように設定を一時的に切り替えます。
  1. テストが終了すると、Testcontainersが起動したデータベースコンテナを片付けてくれます。

Testcontainersのコンテナ起動のポイント

Testcontainersがコンテナを起動するためには、Testcontainersが、macOS(host OS)上で起動しているDockerサーバ(以後Dockerホストと呼ぶ)に対して「このコンテナを起動して」という指示を出せる必要があります。これがVSCode Dev ContainersでTestcontainersを利用する上で大事なポイントになります。

VSCode Dev Containers上でTestcontainersを使う際に起こったエラー

Testcontainersを検証する中で、VSCode Dev Containers上だとうまく動かないポイントがありました。具体的には以下のようなエラーが出ました。

Dockerホストに接続するソケットが見つからない

これは、Testcontainersが、Dockerホストのソケットを見つけられないので、コンテナ起動の指示が出せないというエラーでした。
私達は で開発用コンテナとデータベースコンテナを起動しています。
VSCode Dev Containersが用意する のデフォルトの設定だと、Dockerホストに対するソケットが、開発用コンテナ側にマウントされていないため、上記のようなエラーが出ていました。
この問題は、 のうち、開発用コンテナに をマウントすることで解決しました。

起動したコンテナの疎通確認ができない

上記の問題を解決した後、他のエラーが出ました。
このログは、Testcontainersで最初に起動する、コンテナ片付け用のコンテナ「ryuk」が起動し、その後PostgreSQLのコンテナを起動しようとするも失敗する、というエラーです。
裏側でDocker Desktopのダッシュボードを見ると、PostgreSQLのコンテナは起動していて、死活確認ができないという状況のように見えました。
そこで、 に以下の設定を追記することで、この問題を解決できました。
 
に上記設定を追加することで、開発用コンテナ内部からは というドメインで、Dockerホスト側に接続できるようになります。
これを、 環境変数に設定することで、Testcontainersがコンテナの死活確認をする際の接続先を指定することができます。

サンプルのリポジトリ

上記2点の問題を解決すると、Dev Containers上でTestcontainersを用いたテストを行えるようになりました。
こちらに、VSCode Dev Containersで、Spring Boot + Testcontainersを用いたテストが実行できるサンプルアプリを用意しましたので、他の実装部分について気になる方はご確認ください。

その他

NstockではサーバサイドではJavaで書いていますが、一部運用ツールやバッチ処理などにGolangを利用しています。
Golang用に Testcontainers for Go があり、バッチ処理のテストを書く際にも利用しています。
 
今後、Spring Boot 3系からはTestcontainersをテスト時に利用するコードが書きやすい枠組みが導入されているので、そちらにもチャレンジしていきたいです。

まとめ

Testcontainers (Java版) をVSCode Dev Containers上から利用する場合は、docker compose設定ファイルに以下の設定を追加します。
  • Testcontainersがコンテナ起動の指示を出すため
    • を追加する
  • テスト時に開発用コンテナ内からTestcontainersが起動したコンテナに接続するため
    • を追加する
    • を追加する
 
 
 
Nstockではエンジニアを募集しています!
👨‍👩‍👧‍👦カジュアル面談から気軽にお話しましょう🤞