Golang SQL单元测试与dockertest的基本设置

huangapple go评论141阅读模式
英文:

Basic setup of Golang SQL unit testing with dockertest

问题

我正在使用dockertest进行SQL单元测试。这只是一个简单的连接到*sqlx.DB,但不知何故在连接到数据库时生成了一个错误Error: EOF。我无法确定错误,并且可能配置错误。

import (
	"fmt"
	"log"
	"os"
	"testing"
	
	_ "github.com/lib/pq"
	"github.com/jmoiron/sqlx"
	"github.com/ory/dockertest/v3"
	"github.com/ory/dockertest/v3/docker"
)

var (
	host     = "localhost"
	user     = "postgres"
	password = "postgres"
	dbName   = "db_test"
	port     = "5437"
	dsn      = "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable timezone=UTC connect_timeout=30"
)

var resource *dockertest.Resource
var pool *dockertest.Pool
var testDB *sqlx.DB
var testRepo Repo

func TestMain(m *testing.M) {
	// connect to docker; fail if docker not running
	p, err := dockertest.NewPool("")
	if err != nil {
		log.Fatalf("could not connect to docker; is it running? %s", err)
	}
	pool = p

	opts := dockertest.RunOptions{
		Repository: "postgres",
		Tag:        "14.5", // same as docker compose
		Env: []string{
			"POSTGRES_USER=" + user,
			"POSTGRES_PASSWORD=" + password,
			"POSTGRES_DB=" + dbName,
		},
		ExposedPorts: []string{"5432"},
		PortBindings: map[docker.Port][]docker.PortBinding{
			"5432": {
				{HostIP: "0.0.0.0", HostPort: port},
			},
		},
	}

	resource, err = pool.RunWithOptions(&opts)
	if err != nil {
		// _ = pool.Purge(resource)
		log.Fatalf("could not start resource: %s", err)
	}

	if err := pool.Retry(func() error {
		var err error
		testDB, err = sqlx.Connect("postgres", fmt.Sprintf(dsn, host, port, user, password, dbName))
		if err != nil {
			log.Println("Error:", err)
			return err
		}
		return testDB.Ping()
	}); err != nil {
		_ = pool.Purge(resource)
		log.Fatalf("could not connect to database: %s", err)
	}

	err = createTables()
	if err != nil {
		log.Fatalf("error creating tables: %s", err)
	}

	code := m.Run()

	if err := pool.Purge(resource); err != nil {
		log.Fatalf("could not purge resource: %s", err)
	}

	testRepo = &repo{db: testDB}

	os.Exit(code)
}

func createTables() error {
	tableSQL, err := os.ReadFile("./testdata/tables.sql")
	if err != nil {
		fmt.Println(err)
		return err
	}

	_, err = testDB.Exec(string(tableSQL))
	if err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}

func Test_pingDB(t *testing.T) {
	err := testDB.Ping()
	if err != nil {
		t.Error("can't ping database")
	}
}

英文:

I am performing SQL Unit Testing using dockertest. This is just a simple connection to *sqlx.DB but somehow it is generating an error Error: EOF when connecting to the database. I am unable to identify the error and I may have configured it wrongly.

import (
	"fmt"
	"log"
	"os"
	"testing"
	
	_ "github.com/lib/pq"
	"github.com/jmoiron/sqlx"
	"github.com/ory/dockertest/v3"
	"github.com/ory/dockertest/v3/docker"
)

var (
	host     = "localhost"
	user     = "postgres"
	password = "postgres"
	dbName   = "db_test"
	port     = "5437"
	dsn      = "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable timezone=UTC connect_timeout=30"
)

var resource *dockertest.Resource
var pool *dockertest.Pool
var testDB *sqlx.DB
var testRepo Repo

func TestMain(m *testing.M) {
	// connect to docker; fail if docker not running
	p, err := dockertest.NewPool("")
	if err != nil {
		log.Fatalf("could not connect to docker; is it running? %s", err)
	}
	pool = p

	opts := dockertest.RunOptions{
		Repository: "postgres",
		Tag:        "14.5", // same as docker compose
		Env: []string{
			"POSTGRES_USER=" + user,
			"POSTGRES_PASSWORD=" + password,
			"POSTGRES_DB=" + dbName,
		},
		ExposedPorts: []string{"5432"},
		PortBindings: map[docker.Port][]docker.PortBinding{
			"5432": {
				{HostIP: "0.0.0.0", HostPort: port},
			},
		},
	}

	resource, err = pool.RunWithOptions(&opts)
	if err != nil {
		// _ = pool.Purge(resource)
		log.Fatalf("could not start resource: %s", err)
	}

	if err := pool.Retry(func() error {
		var err error
		testDB, err = sqlx.Connect("postgres", fmt.Sprintf(dsn, host, port, user, password, dbName))
		if err != nil {
			log.Println("Error:", err)
			return err
		}
		return testDB.Ping()
	}); err != nil {
		_ = pool.Purge(resource)
		log.Fatalf("could not connect to database: %s", err)
	}

	err = createTables()
	if err != nil {
		log.Fatalf("error creating tables: %s", err)
	}

	code := m.Run()

	if err := pool.Purge(resource); err != nil {
		log.Fatalf("could not purge resource: %s", err)
	}

	testRepo = &repo{db: testDB}

	os.Exit(code)
}

func createTables() error {
	tableSQL, err := os.ReadFile("./testdata/tables.sql")
	if err != nil {
		fmt.Println(err)
		return err
	}

	_, err = testDB.Exec(string(tableSQL))
	if err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}

func Test_pingDB(t *testing.T) {
	err := testDB.Ping()
	if err != nil {
		t.Error("can't ping database")
	}
}

答案1

得分: 1

pool.Retry的默认最大等待时间是一分钟。只是猜测,也许你的Postgres数据库容器在一分钟内没有启动起来。

尝试使用如下代码增加MaxWait的时间:pool.MaxWait = 20 * time.Minute

英文:

Default max wait time for pool.Retry is one minute. Just guessing, maybe your postgres db container is not coming up in one minute.

Try increasing the MaxWait time with e.g. pool.MaxWait = 20 * time.Minute

huangapple
  • 本文由 发表于 2023年7月1日 17:59:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76594143.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定