• 发生时间:2024-01-25

  • 问题描述:

    • push 服务端代码到 gitlab 远端,跑测试用例时报错:
    2024/01/25 11:44:51 /maker/model/mysqldb/mysqldb_init.go:46
    [error] failed to initialize database, got error dial tcp 192.168.144.3:0: connect: connection refused
    
  • 问题类别:软件测试

  • 原因分析:

    • 从报错信息来看,在跑 testresult 模块的测试用例时,无法连接到 MySQL 数据库,导致以上报错。
    • 首先检查测试环境的 MySQL 数据库是否正常运行:在服务器上执行 docker ps,看到对应的 MySQL 容器是正常运行的。
    • 然后怀疑是环境变量导错了,经过多次确认,容器内/maker 目录下使用的 .env 文件没有问题。
    • 后来怀疑是 LoadEnvBindEnv 的调用顺序有误,但交换顺序后问题仍然存在,说明与此无关。
    • 同时我观察到只有 testresult 模块有这个问题,mysqldb 模块的测试用例能够正常运行,只是 testresult 模块导入环境变量有问题。
    • 添加调试打印,发现 testresult 模块的环境变量是空的,而 mysqldb 模块的环境变量是正确的,说明 testresult 模块导入环境变量失败;
    • testresult 和 mysqldb 模块都是调用 LoadEnv 函数来导入环境变量,为什么前者失败而后者成功呢?
    • 仔细阅读 LoadEnv 函数的代码(如下所示),终于找到原因:LoadEnv 在查找 .env 文件时,最多只搜索2层目录;而 testresult 模块与 .env 文件相差3层目录,导致搜索失败。
    • 而由于我在测试用例中没检查 LoadEnv 的返回值,导致没能发现这个异常。
    // LoadEnv loads the environment variables from .env file.
    func LoadEnv() error {
      envPath, err := myfilepath.FindFileUpward(".env", 3)
      // ...
    }
    
  • 解决方案:

    • LoadEnv 函数增加一个输入参数 level,以控制搜索目录级数;testresult 模块的测试用例在调用 LoadEnv 时,将 level 设置为 5.
  • 实施结果:测试用例运行成功,maker gitlab CI pass。

  • 经验总结:

    • 如果函数的实现逻辑需要用到变量,尽量将其设计为输入参数,而不应该在函数内部写死。尤其要避免在函数调用链的中间写死参数,这种隐晦的操作会给问题定位带来极大的麻烦。