GoFiber v3 + Testcontainers: Air を使用した本番環境のようなローカル開発

イントロ

アプリがデータベースやキューなどの外部サービスに依存している場合、ローカル開発は困難であり、スクリプトが脆弱になったり、一貫性のない環境が発生したりする可能性があります。Fiber v の3 と Testcontainers は、実際のサービスの依存関係をアプリのライフサイクルの一部にし、完全に管理され、再現性があり、開発者にとって使いやすいものにすることで、この問題を解決します。

近日公開予定の v3 リリースで、 Fiber は強力な新しい抽象化を導入します。 Services.これらは、データベース、キュー、クラウド エミュレータなどのバッキング サービスを開始および管理するための標準化された方法を提供し、アプリのライフサイクルの一部としてバッキング サービスを直接管理できるようにし、追加のオーケストレーションは必要ありません。さらにエキサイティングなのは、ServicesTestcontainersを接続する新しいcontribモジュールで、実際のサービスの依存関係をクリーンでテスト可能な方法でスピンアップできます。

この記事では、PostgreSQLコンテナを使用して永続性を実現する小さなFiberアプリを構築し、すべて新しいServiceインターフェースで管理することで、これらの新機能の使用方法を見ていきます。

TLです。博士

  • Fiber v3の新しい Services API を使用して、バッキングコンテナを管理します。
  • testcontainers-goと統合して、PostgreSQLコンテナを自動的に開始します。
  • air を使用したホットリロードを追加すると、ローカル開発ループが高速になります。
  • 開発中にコンテナを再利用するには、Ryuk を無効にし、一貫した名前を付けます。

完全な例はこちら: GitHub リポジトリ

地域開発、最先端の

これは Go での開発に関するブログ記事ですが、他の主要なフレームワークが、異なるプログラミング言語間でもローカル開発にどのようにアプローチしているかを見てみましょう。

Javaエコシステムでは、 Spring BootMicronautQuarkusなどの最も重要なフレームワークには、 Development-time servicesの概念があります。他のエコシステムがこのサービスの概念をどのように処理しているかを見てみましょう。

Spring Bootのドキュメントから:

開発時サービスは、アプリケーションの開発中にアプリケーションを実行するために必要な外部依存関係を提供します。これらは開発中のみ使用されることが想定されており、アプリケーションがデプロイされるときには無効になります。

Micronautは 、テストリソースの概念を使用しています。

Micronautテストリソースは、開発またはテスト中に必要となる外部リソースの管理のサポートを追加します。

たとえば、アプリケーションを実行するためにデータベース (MySQL など) が必要な場合がありますが、そのようなデータベースが開発マシンにインストールされていない場合や、データベースのセットアップと破棄を手動で処理したくない場合があります。

そして最後に、Quarkusには Dev Services の概念も存在します。

Quarkusは、開発モードとテストモードで未設定のサービスの自動プロビジョニングをサポートしています。この機能を Dev Services と呼びます。

最も人気のあるフレームワークの1つである Fiberは、Testcontainersがサポートするサービスのサポートを追加する新しいcontribモジュールを含む、 Servicesの概念を追加しました。

ファイバー v3の新機能

のすべての新機能の中で ファイバー v3、この投稿に関連する2つの主要な機能があります。

  • サービス: 外部リソース(データベースなど)を定義し、構成可能な方法でアプリにアタッチします。この新しいアプローチにより、外部サービスが Fiber アプリで自動的に開始および停止されます。
  • TestcontainersのContribモジュール:Dockerコンテナを使用して実際のバッキングサービスを開始し、アプリのライフサイクルから直接プログラム可能な方法で管理します。

Testcontainersを使用したシンプルなファイバーアプリ

これから構築するアプリケーションは、永続性のためにPostgreSQLコンテナを使用するシンプルなFiberアプリケーションです。これは todo-app-with-auth-form Fiber レシピに基づいていますが、新しい Services API を使用して、インメモリの SQLite データベースではなく、PostgreSQL コンテナを起動します。

プロジェクト構造

.
├── app
|    ├── dal
|    |    ├── todo.dal.go
|    |    ├── todo.dal_test.go
|    |    ├── user.dal.go
|    |    └── user.dal_test.go
|    ├── routes
|    |    ├── auth.routes.go
|    |    └── todo.routes.go
|    ├── services
|    |    ├── auth.service.go
|    |    └── todo.service.go
|    └── types
|         ├── auth.types.go
|         ├── todo.types.go
|         └── types.go
├── config
|    ├── database
|    |    └── database.go
|    ├── config.go
|    ├── config_dev.go
|    ├── env.go
|    └── types.go
├── utils
|    ├── jwt
|    |    └── jwt.go
|    ├── middleware
|    |    └── authentication.go
|    └── password
|         └── password.go
├── .air.conf
├── .env
├── main.go
└── go.mod
└── go.sum

このアプリは /users/todos の複数のエンドポイントを公開し、Testcontainers を使用して開始された PostgreSQL インスタンスにデータを格納します。その組み合わせは次のとおりです。

アプリケーションはレシピに基づいているため、ルート、サービス、およびデータ アクセス層の作成の詳細については省略します。完全なコードは GitHub リポジトリにあります。

代わりに、Testcontainers を使用して PostgreSQL コンテナを起動する方法と、Services API を使用してコンテナのライフサイクルを管理する方法、およびデータ アクセス層がコンテナのライフサイクルを気にせずに使用できるようにする方法について詳しく説明します。さらに、 air を使用して高速なローカル開発エクスペリエンスを実現する方法と、アプリケーションの正常なシャットダウンを処理して、運用環境とローカル開発の構成を分離する方法について説明します。

configパッケージでは、Goビルドタグに応じて、アプリケーションの設定に使用される3つのファイルを定義しています。最初の config/types.go ファイルでは、アプリケーション構成と、サービスの起動とシャットダウンのクリーンアップ関数を保持する構造体を定義します。

package config

import (
	"context"

	"github.com/gofiber/fiber/v3"
)

// AppConfig holds the application configuration and cleanup functions
type AppConfig struct {
	// App is the Fiber app instance.
	App *fiber.App
	// StartupCancel is the context cancel function for the services startup.
	StartupCancel context.CancelFunc
	// ShutdownCancel is the context cancel function for the services shutdown.
	ShutdownCancel context.CancelFunc
}

config.goファイルには、本番環境用の設定があります。

//go:build !dev

package config

import (
	"github.com/gofiber/fiber/v3"
)

// ConfigureApp configures the fiber app, including the database connection string.
// The connection string is retrieved from the environment variable DB, or using
// falls back to a default connection string targeting localhost if DB is not set.
func ConfigureApp(cfg fiber.Config) (*AppConfig, error) {
	app := fiber.New(cfg)

	db := getEnv("DB", "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable")
	DB = db

	return &AppConfig{
		App:            app,
		StartupCancel:  func() {}, // No-op for production
		ShutdownCancel: func() {}, // No-op for production
	}, nil
}

ConfigureApp 関数は Fiber アプリの作成を担当し、main.go ファイルでアプリケーションを初期化するために使用されます。デフォルトでは、 DB 環境変数を使用してPostgreSQLインスタンスへの接続を試み、環境変数が設定されていない場合はローカルのPostgreSQLインスタンスにフォールバックします。また、 StartupCancel フィールドと ShutdownCancel フィールドには空の関数を使用します。これは、本番環境で何もキャンセルする必要がないためです。

go run main.goを使用してアプリを実行すると、デフォルトで!dev タグが適用され、ConfigureApp関数を使用してアプリケーションが初期化されます。ただし、PostgreSQL インスタンスへの接続は失敗するため、アプリケーションは起動しません。

go run main.go

2025/05/29 11:55:36 gofiber-services/config/database/database.go:18
[error] failed to initialize database, got error failed to connect to `user=postgres database=postgres`:
       [::1]:5432 (localhost): dial error: dial tcp [::1]:5432: connect: connection refused
       127.0.0.1:5432 (localhost): dial error: dial tcp 127.0.0.1:5432: connect: connection refused
panic: gorm open: failed to connect to `user=postgres database=postgres`:
               [::1]:5432 (localhost): dial error: dial tcp [::1]:5432: connect: connection refused
               127.0.0.1:5432 (localhost): dial error: dial tcp 127.0.0.1:5432: connect: connection refused

goroutine 1 [running]:
gofiber-services/config/database.Connect({0x105164a30?, 0x0?})
       gofiber-services/config/database/database.go:33 +0x9c
main.main()
       gofiber-services/main.go:34 +0xbc
exit status 2

それを修正しましょう!

ステップ 1: 依存関係を追加する

まず、依存関係が go.mod ファイルに追加されていることを確認する必要があります。

注:ファイバー3 はまだ開発中です。サービスを使用するには、GitHub からメイン ブランチをプルする必要があります。

go get github.com/gofiber/fiber/v3@main
go get github.com/gofiber/contrib/testcontainers
go get github.com/testcontainers/testcontainers-go
go get github.com/testcontainers/testcontainers-go/modules/postgres
go get gorm.io/driver/postgres

ステップ 2: Testcontainers を使用して PostgreSQL サービスを定義する

新しい Services API を活用するには、新しいサービスを定義する必要があります。Services API のドキュメントに示されているように、Fiber アプリによって公開されるインターフェイスを実装することも、次に行うように、Testcontainers contrib モジュールを使用して新しいサービスを作成することもできます。

config/config_dev.goファイルでは、Testcontainers contrib モジュールを使用して、PostgreSQL コンテナをサービスとして Fiber アプリケーションに追加する新しい関数を定義します。このファイルは dev ビルドタグを使用しているため、 airでアプリケーションを起動するときにのみ使用されます。

//go:build dev

package config

import (
	"fmt"

	"github.com/gofiber/contrib/testcontainers"
	"github.com/gofiber/fiber/v3"
	tc "github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/modules/postgres"
)

// setupPostgres adds a Postgres service to the app, including custom configuration to allow
// reusing the same container while developing locally.
func setupPostgres(cfg *fiber.Config) (*testcontainers.ContainerService[*postgres.PostgresContainer], error) {
	// Add the Postgres service to the app, including custom configuration.
	srv, err := testcontainers.AddService(cfg, testcontainers.NewModuleConfig(
		"postgres-db",
		"postgres:16",
		postgres.Run,
		postgres.BasicWaitStrategies(),
		postgres.WithDatabase("todos"),
		postgres.WithUsername("postgres"),
		postgres.WithPassword("postgres"),
		tc.WithReuseByName("postgres-db-todos"),
	))
	if err != nil {
		return nil, fmt.Errorf("add postgres service: %w", err)
	}

	return srv, nil
}

これにより、Fiber がアプリと共に自動的に開始および停止する再利用可能な Service が作成され、アプリケーションが使用する fiber.Config 構造体の一部として登録されます。この新しいサービスでは、testcontainers パッケージの postgres モジュールを使用してコンテナーを作成します。PostgreSQL モジュールの詳細については、 Testcontainers PostgreSQL モジュールのドキュメントを参照してください。

ステップ 3:PostgreSQLサービスを使用してファイバーアプリを初期化する

fiber.Appは、本番環境のConfigureApp機能を使用して、config/config.goファイルで初期化されます。ローカル開発では、代わりに、同じシグネチャを持つ関数を使用してconfig/config_dev.goファイル内のfiber.Appを初期化する必要がありますが、contrib モジュールを使用して PostgreSQL サービスをアプリ設定に追加する必要があります。

サービスの起動とシャットダウンのコンテキストプロバイダーを定義し、カスタム構成を含むPostgreSQLサービスをアプリ構成に追加する必要があります。コンテキストプロバイダーは、サービスの起動とシャットダウンのキャンセルポリシーを定義するのに役立ち、コンテキストがキャンセルされた場合に起動またはシャットダウンをキャンセルできます。コンテキストプロバイダが定義されていない場合、デフォルトでは context.Background().

// ConfigureApp configures the fiber app, including the database connection string.
// The connection string is retrieved from the PostgreSQL service.
func ConfigureApp(cfg fiber.Config) (*AppConfig, error) {
	// Define a context provider for the services startup.
	// The timeout is applied when the context is actually used during startup.
	startupCtx, startupCancel := context.WithCancel(context.Background())
	var startupTimeoutCancel context.CancelFunc
	cfg.ServicesStartupContextProvider = func() context.Context {
		// Cancel any previous timeout context
		if startupTimeoutCancel != nil {
			startupTimeoutCancel()
		}
		// Create a new timeout context
		ctx, cancel := context.WithTimeout(startupCtx, 10*time.Second)
		startupTimeoutCancel = cancel
		return ctx
	}

	// Define a context provider for the services shutdown.
	// The timeout is applied when the context is actually used during shutdown.
	shutdownCtx, shutdownCancel := context.WithCancel(context.Background())
	var shutdownTimeoutCancel context.CancelFunc
	cfg.ServicesShutdownContextProvider = func() context.Context {
		// Cancel any previous timeout context
		if shutdownTimeoutCancel != nil {
			shutdownTimeoutCancel()
		}
		// Create a new timeout context
		ctx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second)
		shutdownTimeoutCancel = cancel
		return ctx
	}

	// Add the Postgres service to the app, including custom configuration.
	srv, err := setupPostgres(&cfg)
	if err != nil {
		if startupTimeoutCancel != nil {
			startupTimeoutCancel()
		}
		if shutdownTimeoutCancel != nil {
			shutdownTimeoutCancel()
		}
		startupCancel()
		shutdownCancel()
		return nil, fmt.Errorf("add postgres service: %w", err)
	}

	app := fiber.New(cfg)

	// Retrieve the Postgres service from the app, using the service key.
	postgresSrv := fiber.MustGetService[*testcontainers.ContainerService[*postgres.PostgresContainer]](app.State(), srv.Key())

	connString, err := postgresSrv.Container().ConnectionString(context.Background())
	if err != nil {
		if startupTimeoutCancel != nil {
			startupTimeoutCancel()
		}
		if shutdownTimeoutCancel != nil {
			shutdownTimeoutCancel()
		}
		startupCancel()
		shutdownCancel()
		return nil, fmt.Errorf("get postgres connection string: %w", err)
	}

	// Override the default database connection string with the one from the Testcontainers service.
	DB = connString

	return &AppConfig{
		App: app,
		StartupCancel: func() {
			if startupTimeoutCancel != nil {
				startupTimeoutCancel()
			}
			startupCancel()
		},
		ShutdownCancel: func() {
			if shutdownTimeoutCancel != nil {
				shutdownTimeoutCancel()
			}
			shutdownCancel()
		},
	}, nil
}

この関数は、次のことを行います。

  • サービスの起動とシャットダウンのコンテキスト プロバイダを定義し、起動とシャットダウン中にコンテキストが実際に使用される場合の起動とシャットダウンのタイムアウトを定義します。
  • PostgreSQL サービスをアプリの構成に追加します。
  • アプリの状態キャッシュから PostgreSQL サービスを取得します。
  • PostgreSQL サービスを使用して接続文字列を取得します。
  • デフォルトのデータベース接続文字列を Testcontainers サービスの文字列で上書きします。
  • アプリの設定を返します。

これにより、PostgreSQLサービスで fiber.App が初期化され、アプリと一緒に自動的に起動・停止されるようになります。PostgreSQLコンテナを表すサービスは、アプリケーション Stateの一部として利用でき、アプリケーションの状態キャッシュから簡単に取得できます。State キャッシュの使用方法の詳細については、 State Managementのドキュメント を参照してください。

ステップ 4: コンテナの再利用によるローカル開発の最適化

config/config_dev.goファイルでは、ローカルでの開発中に同じコンテナを再利用するためにtc.WithReuseByNameオプションが使用されていることに注意してください。これは、アプリケーションの起動時にデータベースの準備が整うのを待つ必要がないようにするのに役立ちます。

また、ホットリロード間のコンテナのクリーンアップを防ぐために、 TESTCONTAINERS_RYUK_DISABLED=true を設定します。の .envファイルで、以下を追加します。

TESTCONTAINERS_RYUK_DISABLED=true

Ryuk は、Testcontainers によって作成された Docker リソースを削除する Testcontainers コンパニオンコンテナです。このユースケースでは、 airを使用してローカルで開発する場合、アプリケーションがホットリロードされるときにコンテナを削除したくないため、Ryuk を無効にし、アプリケーションの複数の実行で再利用される名前をコンテナに付けます。

ステップ 5: PostgreSQL 接続を取得して挿入する

PostgreSQLサービスがアプリケーションの一部になったので、データアクセスレイヤーで使用できます。アプリケーションには、データベース接続文字列を含むグローバル構成変数が config/env.go ファイルにあります。

     // DB returns the connection string of the database.
	DB = getEnv("DB", "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable")

アプリの状態からサービスを取得し、それを使用して接続します。

     // Add the PostgreSQL service to the app, including custom configuration.
	srv, err := setupPostgres(&cfg)
	if err != nil {
		panic(err)
	}

	app := fiber.New(cfg)

	// Retrieve the PostgreSQL service from the app, using the service key.
	postgresSrv := fiber.MustGetService[*testcontainers.ContainerService[*postgres.PostgresContainer]](app.State(), srv.Key())

ここでは、 fiber.MustGetService 関数を使用して State キャッシュから汎用サービスを取得し、それを特定のサービスの種類 (この場合は *testcontainers.ContainerService[*postgres.PostgresContainer]) にキャストする必要があります。

  • testcontainers.ContainerService[T] は、 testcontainers.Container インスタンスをラップする汎用サービスです。これは、 github.com/gofiber/contrib/testcontainersモジュール。
  • *postgres.PostgresContainer は、コンテナの特定のタイプで、この場合は PostgreSQL コンテナです。これは、 github.com/testcontainers/testcontainers-go/modules/postgresモジュール。

postgresSrvサービスを取得したら、それを使用してデータベースに接続できます。ContainerService 型は、サービスからコンテナーをアンラップする Container() method を提供するため、testcontainers パッケージによって提供される API を使用してコンテナーと対話できます。最後に、接続文字列をグローバル DB 変数に渡して、データアクセスレイヤーがそれを使用してデータベースに接続できるようにします。

// Retrieve the PostgreSQL service from the app, using the service key.
	postgresSrv := fiber.MustGetService[*testcontainers.ContainerService[*postgres.PostgresContainer]](app.State(), srv.Key())

	connString, err := postgresSrv.Container().ConnectionString(context.Background())
	if err != nil {
		panic(err)
	}

     // Override the default database connection string with the one from the Testcontainers service.
	config.DB = connString

	database.Connect(config.DB)

ステップ 6:エアーによるライブリロード

air コマンドに build タグを追加して、ローカル開発エクスペリエンスを完成させましょう。アプリケーションのビルドに使用するコマンドに -tags dev フラグを追加する必要があります。.air.confで、-tags devフラグを追加して、開発設定が使用されるようにします。

cmd = "go build -tags dev -o ./todo-api ./main.go"

ステップ 7:グレースフルシャットダウン

ファイバーは、アプリケーションが停止すると、アプリケーションとそのすべてのサービスを自動的にシャットダウンします。ただし、 air シャットダウンをトリガーするための正しい信号をアプリケーションに渡していないため、手動で行う必要があります。

main.go年には、別の GOROUTINE からリッスンする必要があり、割り込みまたは終了シグナルが送信されたときにメインスレッドに通知する必要があります。main関数の最後にこれを追加しましょう。

// Listen from a different goroutine
	go func() {
		if err := app.Listen(fmt.Sprintf(":%v", config.PORT)); err != nil {
			log.Panic(err)
		}
	}()

	quit := make(chan os.Signal, 1)                    // Create channel to signify a signal being sent
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM) // When an interrupt or termination signal is sent, notify the channel

	<-quit // This blocks the main thread until an interrupt is received
	fmt.Println("Gracefully shutting down...")
	err = app.Shutdown()
	if err != nil {
		log.Panic(err)
	}

また、シャットダウンをトリガーするために、 air がアプリケーションに正しい信号を渡していることを確認する必要があります。これを .air.conf に追加して機能させます。

# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = true

これにより、アプリケーションが停止したときに air アプリケーションに割り込み信号を送信するため、アプリケーションを停止したときに airでグレースフルシャットダウンをトリガーできます。

実際の動作を見る

これで、 airでアプリケーションを起動でき、PostgreSQLコンテナが自動的に起動し、アプリケーションを停止するときに正常なシャットダウンを処理します。実際に見てみましょう!

airでアプリケーションを起動しましょう。ログには次のような出力が表示されます。

air

`.air.conf` will be deprecated soon, recommend using `.air.toml`.

 __    _   ___  
/ /\ | | | |_) 
/_/--\ |_| |_| \_ v1.61.7, built with Go go1.24.1

mkdir gofiber-services/tmp
watching .
watching app
watching app/dal
watching app/routes
watching app/services
watching app/types
watching config
watching config/database
!exclude tmp
watching utils
watching utils/jwt
watching utils/middleware
watching utils/password
building...
running...
[DATABASE]::CONNECTED

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[89.614ms] [rows:1] SELECT count(*) FROM information_schema.tables WHERE table_schema = CURRENT_SCHEMA() AND table_name = 'users' AND table_type = 'BASE TABLE'

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44

[31.446ms] [rows:0] CREATE TABLE "users" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"name" text,"email" text NOT NULL,"password" text NOT NULL,PRIMARY KEY ("id"))

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[28.312ms] [rows:0] CREATE UNIQUE INDEX IF NOT EXISTS "idx_users_email" ON "users" ("email")

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[28.391ms] [rows:0] CREATE INDEX IF NOT EXISTS "idx_users_deleted_at" ON "users" ("deleted_at")

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[28.920ms] [rows:1] SELECT count(*) FROM information_schema.tables WHERE table_schema = CURRENT_SCHEMA() AND table_name = 'todos' AND table_type = 'BASE TABLE'

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[29.659ms] [rows:0] CREATE TABLE "todos" ("id" bigserial,"created_at" timestamptz,"updated_at" timestamptz,"deleted_at" timestamptz,"task" text NOT NULL,"completed" boolean DEFAULT false,"user" bigint,PRIMARY KEY ("id"),CONSTRAINT "fk_users_todos" FOREIGN KEY ("user") REFERENCES "users"("id"))

2025/05/29 07:33:19 gofiber-services/config/database/database.go:44
[27.900ms] [rows:0] CREATE INDEX IF NOT EXISTS "idx_todos_deleted_at" ON "todos" ("deleted_at")

   _______ __             
  / ____(_) /_  ___  _____
 / /_  / / __ \/ _ \/ ___/
/ __/ / / /_/ /  __/ /    
/_/   /_/_.___/\___/_/          v3.0.0-beta.4
--------------------------------------------------
INFO Server started on:         http://127.0.0.1:8000 (bound on host 0.0.0.0 and port 8000)
INFO Services:  1
INFO    [ RUNNING ] postgres-db (using testcontainers-go)
INFO Total handlers count:      10
INFO Prefork:                   Disabled
INFO PID:                       36210
INFO Total process count:       1

ターミナルを開いて実行中のコンテナを確認すると、PostgreSQLコンテナが実行されていることがわかります。

docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                       NAMES
8dc70e1124da   postgres:16   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   127.0.0.1:32911->5432/tcp   postgres-db-todos

次の 2 つの重要な点に注意してください。

  • コンテナ名は postgres-db-todos で、これは setupPostgres 関数でコンテナに付けた名前です。
  • コンテナは、標準の PostgreSQL ポート 5432 を、ホスト内の動的に割り当てられたホスト ポート 32911 にマッピングしています。これは、同じ種類の複数のコンテナを実行するときにポートの競合を回避し、実行を決定論的で信頼性の高いものにするための Testcontainers 機能です。詳細については、 Testcontainersのドキュメントを参照してください。

高速開発ループ

ここでアプリケーションを airで停止すると、アプリケーションに実装された正常なシャットダウンのおかげで、コンテナが停止していることがわかります。

しかし、何よりも、 air にリロードを任せてアプリケーションを更新すると、 air アプリケーションがホットリロードされ、PostgreSQLコンテナが再利用されるため、開始されるのを待つ必要はありません。甘い!

GitHub リポジトリで完全な例を確認してください。

統合テスト

このアプリケーションには、データアクセスレイヤーの統合テストが app/dal フォルダーに含まれています。Testcontainersを使用してデータベースを作成し、それを分離してテストします。次のようにしてテストを実行します。

go test -v ./app/dal

10秒も経たないうちに、クリーンなデータベースが作成され、永続性レイヤーが期待どおりに動作することが確認されました。

Testcontainersのおかげで、テストはアプリケーションと並行して実行でき、それぞれがランダムなポートを持つ独自の分離コンテナを使用します。

結論

Fiber v3のサービスの抽象化と Testcontainers を組み合わせることで、シンプルで本番環境のようなローカル開発エクスペリエンスが実現します。手作りのスクリプトや同期していない環境はもうありません - どこでもクリーンに実行されるGoコードだけで、「クローン&実行」のエクスペリエンスを提供します。さらに、Testcontainersを使用すると、統合テストとローカル開発の両方で統一された開発者エクスペリエンスが提供され、実際の依存関係を使用してアプリケーションをクリーンかつ決定論的にテストする優れた方法が提供されます。

本番環境とローカル開発の構成を分離しているため、同じコードベースで両方の環境をクリーンにサポートでき、開発専用のツールや依存関係で本番環境を汚染することはありません。

次は何ですか?

フィードバックがある場合、またはFiber v3の使用方法を共有したいですか?GitHub リポジトリでコメントをドロップするか、問題を開いてください。

投稿カテゴリ

関連記事