You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Dockertest配置Golang SQL单元测试时遇EOF连接错误

解决Dockertest连接PostgreSQL时的"Error: EOF"问题

出现"Error: EOF"通常是因为数据库容器未正常启动、端口映射错误,或者连接时数据库服务还未就绪。针对你的代码,主要问题出在硬绑定固定端口和端口获取方式错误,以下是具体修复方案:

关键修复点

  • 移除硬编码的固定端口,改用Dockertest动态分配端口,避免端口冲突
  • 通过容器实例获取实际映射的端口,确保连接到正确的端口
  • 可选:增加重试次数,适配数据库启动的耗时

修改后的代码

1. 调整全局变量

去掉固定的port变量,改为动态获取:

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

2. 修改容器启动与端口获取逻辑

在启动容器后,通过resource.GetPort获取实际映射的端口:

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
    // 可选:增加重试次数,确保等待数据库完全启动
    pool.MaxRetries = 10

    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"},
        // 移除硬绑定的HostPort,让Docker自动分配可用端口
        PortBindings: map[docker.Port][]docker.PortBinding{
            "5432": {
                {HostIP: "0.0.0.0"},
            },
        },
    }

    resource, err = pool.RunWithOptions(&opts)
    if err != nil {
        log.Fatalf("could not start resource: %s", err)
    }
    // 获取容器实际映射的5432端口
    port := resource.GetPort("5432/tcp")

    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)
    }

    testRepo = &repo{db: testDB}
    code := m.Run()

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

    os.Exit(code)
}

其他排查建议

  • 检查本地原固定端口(如5437)是否被其他进程占用:Linux/macOS用lsof -i :5437,Windows用netstat -ano | findstr :5437
  • 查看容器日志确认Postgres状态:docker logs <容器ID>,日志出现database system is ready to accept connections说明服务就绪

内容的提问来源于stack exchange,提问作者Jessica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 15:42:02