如何将Golang包测试数据文件分享给消费者?

How to share Golang package test data files with consumers?

我们创建了一个私有 go 库(实用程序包)以在服务之间共享通用 api 方法和业务逻辑。在实用程序包中,我们在“.json”文件中有数十个模拟 JSON 响应,用于模拟 api 测试。

使用此实用程序包的服务也希望访问相同的模拟文件,因为它们依赖相同的模拟 api 响应来测试各种内部业务逻辑。有没有一种方法可以通过一些相对文件路径或预编译它们(字节或字符串)来共享这些文件,以允许消费者测试通过标准 pkg 变量或引用相同的 .json 文件(文件路径或数据)方法,通过 go get github.com/whatever/utility-library?

导入后

理想情况下,消费者测试可以通过子包(如“http/httptest”)访问这些文件,然后在自己的模拟服务器中引用内部 .json 文件(如httptest.GetBusinessObject.Response []byteResponseFilePath string,等等)。我们希望继续将模拟响应存储在同一实用程序模块中的 .json 文件中,但只是将它们公开给消费者测试文件,严格用于测试目的。

my-api-pkg
├── go.mod
└── api
    └── api.go
    └── api_test.go // <= we currently access .json files here like utiltest.apiResponse []byte
    └── apitest // <= sub pkg that contains testing methods and .json accessors
        └── apitest.go
        └── responses
            └── api.response.json
my-service-pkg
├── go.mod
├── server.go
├── server_test.go
└── sub-pkg
    └── subpkg.go
    └── subpkg_test.go // <= want to access utiltest.apiResponse []byte for api mocks here

Non-Go 文件和 _test.go 文件不会编译成模块。要发布 _test.go 文件,请将它们重命名为 .go 文件并导出要向客户公开的变量和函数。

对于非 Go 文件,从 Go 1.16 开始,embed 它们:

package mycompany.com/common/testing

import _ "embed"

//go:embed responses/api.response.json
var MockApiJsonResponse []byte // or string

目录树如下所示:

testing 
└── testing.go
└── responses
    └── api.response.json

然后您的客户将能够像往常一样引用那些导出的变量和函数:

package mycompany.com/service

import (
    "testing"
    common_testing "mycompany.com/common/testing"
)

func TestThings(t *testing.T) {
    mock := common_testing.MockApiJsonResponse
    // ...
}

原答案!看来我的问题是我的 apitest 包中有一个导入的实用程序 fn,来自它自己的内部 testing.go 文件,这意味着它的 init() 函数是 运行 并污染了上游pkg 测试运行。

我最初的方法是合理的,但是 erptest pkg 不再被下载到上游服务 在我删除它的内部 testing.go 导入 之后。我更改了结构以像这样在根目录中引用测试目录,这恢复了 apitest pkg 的上游下载:

/my-api-pkg
├── go.mod
└── /api
    └── api.go
    └── api_test.go // <= we currently access .json files here like utiltest.apiResponse []byte
    └── /apitest // <= sub pkg that contains testing methods and .json accessors
        └── apitest.go
└── /testing // <= moving the files here re-enabled download and access or erptest code to upstream consumers
    └── /files
        └── /api.response.json

这是我的 apitest pkg 导出的基本结构,以允许通过 apitest.Domain().GetApiRoute1.Res1

访问上游文件(作为 []byte)
// accessor
type domainAccessor struct {
    GetApiRoute1 getApiRoute1
    ...
}

func DomainAccessor() domainAccessor {
    return domainAccessor{
        GetApiRoute1: _GetApiRoute1,
        ...
    }
}

// individual file accessors for each route
type getApiRoute1 struct {
    Res1 []byte
    Res2 []byte
}

var _GetApiRoute1 = getApiRoute1{
    Res1: loadFile("testing/files/api/v1/domain/getApiRoute1.res.json"),
    Res2: loadFile("testing/files/api/v1/domain/getApiRoute2.res.json"),
}

loadfile fn 读取文件到[]byte

func loadFile(filepath string) []byte {
    dir := ""
    _, filename, _, ok := runtime.Caller(0)
    if ok {
        dir = path.Join(path.Dir(filename), "..", "..", "..")
    }
    fullPath := path.Join(dir, filepath)
    body, err := ioutil.ReadFile(fullPath)
    if err != nil {
        log.Println("Error apitest.loadFile: unable to read file", err)
        panic(err)
    }
    return body
}