【问题标题】:Problem with resolving relative paths in non-main package解决非主包中的相对路径的问题
【发布时间】:2026-02-13 18:10:01
【问题描述】:

我在解析 Go 应用程序中的相对文件路径时遇到问题。对于这个应用程序,我决定制作一个包,为不同的配置文件提供统一的接口。 conf 包包含相关的数据文件,所以这基本上是文件树:

app/conf
    + config.go
    + config.json
    + ...
app/code
    + code.go
    + code_test.go

问题是,当app/code/code_test.go 中定义的测试调用app/conf 包中的函数时,该函数又试图打开app/conf/config.json,由于工作目录位于app/code,因此相对路径被弄乱了。

  • 我查看了其他 SO 答案,其中提到了 path/filepath 包,尤其是 filepath.Abs function 用于将相对路径转换为绝对路径。但是,这并不能解决我的问题,因为绝对路径将基于错误的工作目录。

  • 一些基于 GOPATH 的 “绝对路径” 解决方案可能就足够了,但我想在构建和导出代码时 GOPATH 将没有什么意义。

    李>
  • 简单地将所有配置文件移植到硬编码的 Go 结构中也不可行,因为它们是跨语言使用的。

【问题讨论】:

  • 你只有在你的测试文件中有这个问题吗?我问是因为它们不包含在最终版本中。所以在你构建和部署你的应用程序之后,将没有code_test.go 来执行app/conf 中的函数...
  • @mkopriva 对不起,我不清楚,这些函数是从实际的实施文件中调用的(在上面的例子中是code.go),但是这些函数也会从实际的main 包中调用,即不仅在测试中。
  • 然后您可以指示您的用户将配置文件安装在已知位置,无论是绝对位置还是相对于二进制文件的位置由您决定。或者,您可以指示您的用户提供配置的位置,作为 cli arg 或 env var,或两者兼而有之。
  • ... 第三种选择是将配置“嵌入”到最终的二进制文件中。 go 命令不支持开箱即用,但有 3rd 方库可以为您做到这一点。
  • 是的,谢谢,我正在考虑这样的解决方案;例如指导用户定义一些环境变量等,但我想知道是否有更好和更传统的解决方案,对 Go 来说更“原生”。

标签: go relative-path


【解决方案1】:

依赖源代码中的配置文件路径不仅是单元测试中的问题,而且在生产中也是一个问题。通常,代码会执行以下操作:

  • 配置处理程序接受一个io.Reader,它将从中读取配置。
  • main 将打开一个文件(其路径可能是硬编码的、通过命令行传递、通过 env var 传递等)并将其传递给配置处理程序以供读取。
  • 配置处理程序的单元测试会将一个配置(或多个配置,以测试不同的场景)硬编码为类似bytes.Buffer 的内容,然后将其传递给配置处理程序以进行读取。
  • 单元测试除了读取配置文件的代码(因此,任何使用配置但不操作配置),将生成@987654324 @struct 在代码中,而不是从真正的 假文件中读取它,作为测试工具的一部分。例如,myConf := config.Config{SomeProp: "foo", OtherProp: true},然后将其传递给被测函数。

【讨论】:

  • 谢谢阿德里安,很好的回答。我正在寻找一种方法来动态地将我的测试基于配置,而不是在测试中针对静态配置值进行显式测试,因为无论如何大部分配置都将保持不变。但我想这背后的动机是方便。
  • 为了方便起见,没有理由不能定义结构文字并在多个测试(甚至跨多个包)中重用它。
  • 一些行为测试依赖于高度个性化的 ICC 配置文件,该配置文件是配置的一部分,适用于运行测试的系统。因此,这些配置文件不能硬编码,以免测试套件变得非常不稳定。因此,虽然我认为我已经找到了一种方法来根据您的建议对系统的某些部分进行建模,但我很难理解在测试这些组件期间如何避免动态配置。
  • 如果不知道更多,我所能建议的就是重构您的代码以减少环境特定(即测试不需要依赖于运行它的系统的配置文件) .单元测试应在任何系统上 100% 可重现,无需针对系统进行更改。
  • 好的,无论如何感谢您的帮助。这些组件在屏幕上执行图像识别,需要一些基本测试,但这些测试不是,也永远不会是正确的单元测试。