Go甚のTestcontainersでのモゞュヌルの䜜成

投皿日: 5月 4, 2023

倚くの堎合、プロゞェクトは特定のテクノロゞに非垞に反埩的な方法で䟝存しおおり、そのテクノロゞず察話するためにコヌドを 1 ぀のプロゞェクトから別のプロゞェクトに移動する状況に陥る可胜性がありたす。 「このコヌドをラむブラリにパッケヌゞ化しお、どこでも利甚しおみおはどうだろうか」

そのずき、モゞュヌル性、デカップリング、凝集性など、特定の゜フトりェア゚ンゞニアリングのベストプラクティスを思い出すのです。

このブログ蚘事では、 Testcontainers for Goの新しいモゞュヌルを䜜成し、プロゞェクトで䜿甚するテクノロゞヌず、コヌドをテストするためのテクノロゞヌを衚す方法に぀いお説明したす。

banner Testcontainers for Goでのモゞュヌルの䜜成

モゞュヌルを最初から䜜成する

Testcontainers for Go モゞュヌルは、特定のテクノロゞの API を公開する Go モゞュヌルにすぎたせん。 Go モゞュヌルをれロから簡単に䜜成できるように、Testcontainers for Go には、関心のあるモゞュヌルのコヌドのスキャフォヌルディングを生成するコマンドラむン ツヌルが甚意されおいるため、すぐに開始できたす。

このツヌルは以䞋を生成したす。

  • このテクノロゞヌのGoモゞュヌルには、次のものが含たれたす。
    • go.mod Go甚のTestcontainersの珟圚のバヌゞョンを含む go.sum ファむル。
    • モゞュヌルにちなんで名付けられた小文字の Go パッケヌゞ。
    • コンテナを䜜成するための Go ファむルで、むメヌゞ フラグの倀が Docker むメヌゞずしお䜿甚される専甚の構造䜓を䜿甚したす。
    • コンテナの簡単なテストを実行するためのGoテストファむルで、䞊蚘の構造䜓を消費したす。
    • 䞀貫した方法でテストを実行するための Makefile。
  • docs/modulesディレクトリ内のマヌクダりンファむルには、コンテナの䜜成ず簡単なテストの䞡方のスニペットが含たれおいたす。デフォルトでは、この生成されたファむルには、以䞋を含むモゞュヌルのすべおのドキュメントが含たれたす。
    • モゞュヌルが远加された Testcontainers for Go のバヌゞョン。
    • モゞュヌルの簡単な玹介です。
    • プロゞェクトの䟝存関係にモゞュヌルを远加するためのセクション。
    • Go モゞュヌルの examples_test.go ファむルからコンテナを䜜成するためのスニペットを含む、䜿甚䟋のセクション。
    • コンテナを䜜成するための゚ントリポむント関数や、コンテナを䜜成するためのオプションなど、モゞュヌル参照のセクション。
    • コンテナメ゜ッドのセクションです。
  • ドキュメント サむト内のモゞュヌルの新しい Nav ゚ントリで、プロゞェクトのルヌト ディレクトリにある mkdocs.yml ファむルに远加したす。
  • .github/workflows内の GitHub ワヌクフロヌ ファむル ディレクトリに移動しお、テクノロゞのテストを実行したす。
  • プロゞェクトのワヌクスペヌスに新しいモデルを含めるための VSCode ワヌクスペヌス ファむル内の゚ントリ。

コヌド生成ツヌル

コヌド生成ツヌルは、Goの䟝存関係がTestcontainers for Goに分散されるのを避けるために、Goモゞュヌルずしお modulegen ディレクトリに存圚するGoプログラムであり、その唯䞀の目的は、Goテンプレヌトを䜿甚しおGoモゞュヌルのスキャフォヌルディングを䜜成するこずです。

コヌド生成ツヌルのコマンドラむン フラグを衚 1に瀺したす。

旗皮類必須圢容
–名前糞はいモゞュヌルの名前。必芁に応じおキャメルケヌスを䜿甚しおください。 英数字のみを䜿甚できたす (先頭の文字は文字である必芁がありたす)。
–画像 糞はいモゞュヌルが䜿甚する Docker むメヌゞの完党修食名 ( docker.io/org/project:tag)
–タむトル糞いいえ倧文字ず小文字の混圚をサポヌトする名前のバリアント (MongoDB など)。 英数字のみを䜿甚できたす (先頭の文字は文字である必芁がありたす)。
衚 1: コヌド生成ツヌルのコマンド ラむン フラグ。

モゞュヌル名たたはタむトルに英数字が含たれおいない堎合、プログラムは生成を終了したす。 たた、モゞュヌルがすでに存圚する堎合は、既存のファむルを曎新せずに終了したす。

modulegenディレクトリから、次のコマンドを実行したす。

go run . new module --name ${NAME_OF_YOUR_MODULE} --image "${REGISTRY}/${MODULE}:${TAG}" --title ${TITLE_OF_YOUR_MODULE}

モゞュヌルぞの型ずメ゜ッドの远加

モゞュヌルに型ずメ゜ッドを远加する際に埓うべき䞀連の手順を提案したす。

  1. モゞュヌルにパブリック Container タむプが存圚するこずを確認したす。 このタむプは、 testcontainers.Container タむプを埋め蟌むためにコンポゞションを䜿甚し、そこからすべおの方法を促進する必芁がありたす。
  2. RunContainer関数が存圚し、パブリックであるこずを確認しおください。この関数はモゞュヌルぞの゚ントリポむントであり、むメヌゞ、デフォルトの公開ポヌト、埅機戊略など、 testcontainers.GenericContainerRequest 構造䜓の初期倀を定矩したす。 その結果、関数はコンテナリク゚ストをデフォルト倀で初期化する必芁がありたす。
  3. モゞュヌルのコンテナオプションを定矩するには、 testcontainers.ContainerCustomizer むンタヌフェヌスを䜿甚したす。このむンタヌフェヌスには Customize(req *GenericContainerRequest) error ぀の方法がありたす。

手蚘 オプションのベスト プラクティスは、With プレフィックスを䜿甚しお関数を定矩し、倉曎された testcontainers.GenericContainerRequest 型を返す関数を返すこずであるず考えおいたす。 そのため、ラむブラリにはContainerCustomizerむンタヌフェむスを実装するtestcontainers.CustomizeRequestOption型がすでに甚意されおいるため、この型を䜿甚しお独自のカスタマむザヌ関数を䜜成するこずをお勧めしたす。

  1. 同時に、モゞュヌル甚に独自のコンテナカスタマむザヌを䜜成する必芁がある堎合がありたす。 testcontainers.ContainerCustomizerむンタヌフェヌスを実装しおいるこずを確認したす。独自のカスタマむザヌ関数を定矩するこずは、コンテナの ContainerRequest に存圚しない特定の状態を転送する必芁がある堎合や、堎合によっおは䞭間の Config 構造䜓を䜿甚する必芁がある堎合に䟿利です。 以䞋のスニペットで MyCustomizer ず WithMy を芋おみたしょう。
  2. オプションは、Go コンテキストの埌に可倉個匕数ずしお RunContainer 関数に枡され、for ルヌプを䜿甚しお最初の testcontainers.GenericContainerRequest 構造䜓を定矩した盎埌に凊理されたす。
  3. 必芁に応じお、 Container 型をレシヌバヌずしお䜿甚しお、実行䞭のコンテナから情報を抜出するパブリックメ゜ッドを定矩したす。 たずえば、デヌタベヌスにアクセスするための接続文字列が圹立぀方法ずしお考えられたす。 コンテナメ゜ッドを远加する際には、ナヌザヌにずっお䜕が圹立぀かを考えおください。
  4. 公開APIをGoコメントで文曞化したす。
  5. モゞュヌルの新しい API を説明するためにドキュメントを拡匵したす。 コヌド生成ツヌルでは、Container options サブセクションず Container methods サブセクションを含む芪 Module reference セクションがすでに䜜成されおいたす。各サブセクション内で、各オプションずメ゜ッドのネストされたサブセクションをそれぞれ定矩しおください。

次のスニペットは、コヌドがどのように芋えるかの䟋を瀺しおいたす。

type ModuleContainer struct {
   testcontainers.Container
   cfg *Config
}
// Config type represents an intermediate struct for transferring state from the options to the container
type Config struct {
   data string
}
// RunContainer is the entrypoint to the module
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
   cfg := Config{}
   req := testcontainers.ContainerRequest{
       Image: "my-image",
       //...
   }
   genericContainerReq := testcontainers.GenericContainerRequest{
       ContainerRequest: req,
       Started:          true,
   }
   //...
   for _, opt := range opts {
       if err := opt.Customize(&genericContainerReq); err != nil {
       	return nil, err
       }
       // If you need to transfer some state from the options to the container, you can do it here
       if myCustomizer, ok := opt.(MyCustomizer); ok {
           config.data = customizer.data
       }
   }
   //...
   container, err := testcontainers.GenericContainer(ctx, genericContainerReq)
   //...
   moduleContainer := &Container{Container: container}
   // use config.data here to initialize the state in the running container
   //...
   return moduleContainer, nil
}
// MyCustomizer type represents a container customizer for transferring state from the options to the container
type MyCustomizer struct {
   data string
}
// Customize method implementation
func (c MyCustomizer) Customize(req *testcontainers.GenericContainerRequest) testcontainers.ContainerRequest {
   req.ExposedPorts = append(req.ExposedPorts, "1234/tcp")
   return req.ContainerRequest
}
// WithMy function option to use the customizer
func WithMy(data string) testcontainers.ContainerCustomizer {
   return MyCustomizer{data: data}
}
// WithSomeState function option leveraging the functional option
func WithSomeState(value string) testcontainers.CustomizeRequestOption {
   return func(req *testcontainers.GenericContainerRequest) {
       req.Env["MY_ENV_VAR"] = value
   }
}
// ConnectionString returns the connection to the module container
func (c *Container) ConnectionString(ctx context.Context) (string, error) {...}

ContainerRequest オプション

特定のモゞュヌルのコンテナの䜜成を簡略化するために、Testcontainers for Go には、モゞュヌルのコンテナリク゚ストをカスタマむズするための䞀連の testcontainers.CustomizeRequestOption 関数が甚意されおいたす。 これにより、サヌビスのコンテナリク゚ストを完党にカスタマむズできたす。

これらのオプションは次のずおりです。

  • testcontainers.WithImage: コンテナリク゚ストのむメヌゞを蚭定する関数。
  • testcontainers.WithImageSubstitutors: コンテナむメヌゞに独自の眮換を蚭定する関数。
  • testcontainers.WithEnv: コンテナリク゚ストの環境倉数を蚭定する関数。
  • testcontainers.WithHostPortAccess: ホストで既に実行されおいるポヌトにコンテナがアクセスできるようにする関数。
  • testcontainers.WithLogConsumers: コンテナリク゚ストのログコンシュヌマを蚭定する関数。
  • testcontainers.WithLogger: コンテナリク゚ストのロガヌを蚭定する関数。
  • testcontainers.WithWaitStrategy: コンテナリク゚ストの埅機ストラテゞヌを蚭定する関数で、枡されたすべおの埅機ストラテゞヌをコンテナリク゚ストに远加し、期限が 60 秒のtestcontainers.MultiStrategyを䜿甚したす。詳现に぀いおは 、埅機戊略 を参照しおください。
  • testcontainers.WithWaitStrategyAndDeadline: 枡された期限を持぀ testcontainers.MultiStrategy を䜿甚しお、枡されたすべおの埅機ストラテゞヌをコンテナリク゚ストに远加し、コンテナリク゚ストの埅機ストラテゞヌを蚭定する関数。 詳现に぀いおは 、埅機戊略 を参照しおください。
  • testcontainers.WithStartupCommand: コンテナの起動時にコマンドの実行を蚭定する関数。
  • testcontainers.WithAfterReadyCommand: コンテナの準備ができた (埅機戊略が満たされおいる) 盎埌にコマンドの実行を蚭定する関数。
  • testcontainers.WithNetwork: コンテナリク゚ストのネットワヌクずネットワヌク゚むリアスを蚭定する関数。
  • testcontainers.WithNewNetwork: コンテナリク゚ストの䜿い捚おネットワヌクのネットワヌク゚むリアスを蚭定する関数。
  • testcontainers.WithConfigModifier: コンテナリク゚ストの蚭定Dockerタむプを蚭定する関数。 詳现に぀いおは、「 詳现蚭定 」を参照しおください。
  • testcontainers.WithEndpointSettingsModifier: コンテナリク゚ストの゚ンドポむント蚭定の Docker タむプを蚭定する関数。 詳现に぀いおは、「 詳现蚭定 」を参照しおください。
  • testcontainers.WithHostConfigModifier: コンテナリク゚ストのホスト蚭定 Docker タむプを蚭定する関数。 詳现に぀いおは、「 詳现蚭定 」を参照しおください。
  • testcontainers.CustomizeRequest: デフォルトの testcontainers.GenericContainerRequest をナヌザヌが提䟛するものずマヌゞする関数。 コンテナリク゚ストを完党にカスタマむズする堎合に掚奚されたす。

それらのいずれかを䜿甚しお、 RunContainer 関数を呌び出すずきにコンテナをカスタマむズできたす。 LocalStack モゞュヌルの䟋を次に瀺したす。

container, err := localstack.RunContainer(ctx,
testcontainers.WithImage("localstack/localstack:2.0.0"),
testcontainers.WithEnv(map[string]string{"SERVICES": "s3,sqs"}),
)

結論

この蚘事では、Testcontainers for Go の Go モゞュヌルを䜜成し、カスタム型、メ゜ッド、カスタマむザヌを远加する方法を共有したした。 最埌に、コヌド生成ツヌルを䜿甚しお新しいモゞュヌルのスキャフォヌルディングを䜜成する方法を発芋したした。

モゞュヌルに぀いおもっず知りたいですか? 次のリンクを確認しおください。

さらに詳しく

関連蚘事