Golang测试与示例代码实践指南

Golang测试与示例代码实践指南 我有一个项目,其简化结构如下:

chessImager
  ..
  examples (文件夹)
  tests (文件夹)
  ...
  chessImager.go
  ...

如果我在 tests 文件夹中运行 go test ./...,所有测试都能正常工作。但是,如果我在 chessImager 文件夹中运行 go test ./...,则会收到以下错误:

# github.com/Hultan/chessImager/examples
examples/medium.go:10:6: main redeclared in this block
	examples/advanced.go:10:6: other declaration of main
examples/other.go:10:6: main redeclared in this block
	examples/advanced.go:10:6: other declaration of main
examples/simple.go:10:6: main redeclared in this block
	examples/advanced.go:10:6: other declaration of main
?   	github.com/Hultan/chessImager	[no test files]
ok  	github.com/Hultan/chessImager/test	1.997s
FAIL

examples 文件夹不包含任何可测试文件(*_test.go),那么为什么会抱怨这个文件夹呢?我是否应该为每个示例创建子文件夹,以避免此类问题?

我的项目:

GitHub - Hultan/chessImager: ChessImager is a Go package that creates images...

ChessImager 是一个 Go 包,它根据 FEN 字符串创建棋盘图像。它具有高度可配置性,因此您可以创建外观完全符合您期望的棋盘图像…


更多关于Golang测试与示例代码实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

Go test 在使用通配符语法时,也会尝试构建所有包,正如您所做的那样。如果您不希望它尝试构建 main 包,那么您必须逐个指定包。

更多关于Golang测试与示例代码实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是因为示例目录中的所有文件都被声明为 package main 并且属于同一个包。Go 会尝试将它们一起编译,但当它第二次遇到 main 时就会失败。我建议在示例目录中为每个包含 main 函数的示例创建一个子目录。

Go 测试在使用通配符语法指定时,也会尝试构建所有包。如果你不希望它尝试构建主包,那么你必须逐个指定包。

那么这就是此行为的原因。

我之前提到了 examples_test.go,但该测试文件在测试文件中包含了示例代码的副本,因此不应触发构建 examples 文件夹。我第一次回复时手头没有代码。

感谢帮助…

我理解那部分,让我澄清一下我的问题。

示例文件夹中没有可测试的文件(没有以 _test 结尾的文件),所以我想知道的是,为什么它甚至要尝试编译那个文件夹?

我以为它会寻找测试文件,然后编译测试所需的内容?

就在我写下上一句话时,我想我意识到问题所在了。我有一个名为 examples_test.go 的文件,它测试示例是否正常工作。这个测试肯定触发了对示例文件夹的编译。

所以,你建议为每个示例使用子文件夹应该能解决这个问题……谢谢……

问题在于 examples 目录下包含多个 main 函数,当 Go 工具链尝试编译整个包时会产生冲突。go test ./... 会递归编译所有子目录,而 examples 目录被当作一个独立的包处理。

解决方案

1. 为每个示例创建独立子目录(推荐)

examples/
├── simple/
│   ├── main.go
│   └── go.mod
├── medium/
│   ├── main.go
│   └── go.mod
└── advanced/
    ├── main.go
    └── go.mod

每个子目录都需要自己的 go.mod

// examples/simple/go.mod
module github.com/Hultan/chessImager/examples/simple

go 1.21

replace github.com/Hultan/chessImager => ../..

require github.com/Hultan/chessImager v0.0.0

2. 使用构建标签隔离示例

在每个示例文件顶部添加构建标签:

// examples/simple.go
//go:build example_simple

package main

func main() {
    // 简单示例代码
}
// examples/medium.go  
//go:build example_medium

package main

func main() {
    // 中等示例代码
}

然后通过标签单独运行:

go run -tags=example_simple examples/simple.go

3. 使用 _test 后缀重命名示例文件

将示例文件重命名为 *_example_test.go,Go 测试工具会将其视为示例代码:

// examples/simple_example_test.go
package examples_test

import (
    "fmt"
    "testing"
)

func ExampleSimple() {
    fmt.Println("Simple example output")
    // Output: Simple example output
}

4. 排除 examples 目录测试

在根目录创建 .go.test 配置文件:

// .go.test
{
    "exclude": [
        "examples"
    ]
}

或者使用命令行排除:

go test ./... -exclude ./examples

实际修复示例

基于你的项目结构,建议采用方案1:

# 重构 examples 目录
mkdir -p examples/{simple,medium,advanced,other}

# 移动文件并添加 go.mod
mv examples/simple.go examples/simple/main.go
mv examples/medium.go examples/medium/main.go
mv examples/advanced.go examples/advanced/main.go  
mv examples/other.go examples/other/main.go

# 为每个示例创建 go.mod
for dir in simple medium advanced other; do
    cat > examples/$dir/go.mod << EOF
module github.com/Hultan/chessImager/examples/$dir

go 1.21

replace github.com/Hultan/chessImager => ../..

require github.com/Hultan/chessImager v0.0.0
EOF
done

这样修改后,go test ./... 将正常工作,同时保持示例代码的可执行性。

回到顶部