Golang测试套件使用指南
Golang测试套件使用指南 大家好,
我已经使用 ozontech/allure-go 在内部包中编写了10个测试套件。我希望能够从 main.go 执行所有这些测试套件,而不使用命令行工具,以便完全控制测试的执行过程。请问是否有人实现过任何自定义代码来实现这个功能?
感谢您的回复。实际上我完全同意您的观点,我也有同样的场景,需要为多个微服务编写多个测试套件。我想要的是能够整体执行这些测试套件。例如,我有 testsuite1、testsuite2、testsuite3……等等,每个测试套件包含 10 个测试用例(即测试方法)。我想运行 testsuite1 和 testsuite2 中的几个测试用例,但还没有找到任何解决方案。举个例子,如果我们使用 Cucumber,我们可以基于标签来执行特定的测试用例,这非常容易实现。
更多关于Golang测试套件使用指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,我其实不太明白你所说的“测试套件”具体指什么,但我可以举一个例子,或许能帮到你。
我们通常将运行速度足够快的测试写在 _test.go 文件中,这是避免测试代码分离和变得混乱的最简单方法。在这种情况下,我们运行:
go test ./... -race -parallel
然而我们都知道,在开发过程中的某个阶段,如果你有 3-5 个微服务(大多数公司可能只有一个单体应用,所以你可能不需要创建端到端测试),你会开始创建涉及多个系统的更大规模的测试。有些公司称之为集成测试,有些称之为端到端测试,有些称之为系统测试,等等。它们的共同点是,一个测试用例完成所需的时间远不止眨眼那么快。
在这种情况下,在项目根目录创建一个 /tests 目录是完全没有问题的。这样,你本地运行快速测试的工作流程就变成了:运行除了 /tests 目录(也就是你那些非单元测试的大型测试套件)之外的所有测试。
go test $(go list ./… | grep -v /tests/)
你不应该试图完全控制 Go 语言本身提供的测试执行流程之外的东西。Go 已经很好地处理了缓存、竞态条件、并行化以及设置/拆卸阶段。
希望这能帮到你。在我看来,你并不需要:
- GitHub - ozontech/allure-go: 一个完整的 Go 语言 Allure 提供程序,不会过度增加接口使用的负担 或者
- GitHub - stretchr/testify: 一个包含通用断言和模拟的工具包,与标准库配合良好
强烈不建议使用那些自称是测试框架的东西,因为测试框架的功能已经内置于语言之中了。
在Golang中,你可以通过自定义测试运行器来执行测试套件,而不依赖命令行工具。以下是一个实现方案:
package main
import (
"fmt"
"os"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)
// 定义你的测试套件接口
type TestSuite interface {
TestAll(t *testing.T)
}
// 自定义测试运行器
type CustomTestRunner struct {
suites []TestSuite
}
func NewCustomTestRunner() *CustomTestRunner {
return &CustomTestRunner{
suites: make([]TestSuite, 0),
}
}
func (r *CustomTestRunner) AddSuite(suite TestSuite) {
r.suites = append(r.suites, suite)
}
func (r *CustomTestRunner) RunAll() bool {
allPassed := true
for _, suite := range r.suites {
fmt.Printf("Running test suite...\n")
// 创建testing.T实例
t := &testing.T{}
// 运行测试套件
suite.TestAll(t)
if t.Failed() {
allPassed = false
fmt.Printf("Test suite failed\n")
} else {
fmt.Printf("Test suite passed\n")
}
}
return allPassed
}
// 示例测试套件1
type MyTestSuite1 struct {
suite.Suite
}
func (s *MyTestSuite1) TestAll(t *testing.T) {
s.Run(t, "TestExample1", func(t provider.T) {
t.Epic("Example")
t.Feature("Test Suite 1")
t.Title("Test Example 1")
// 你的测试逻辑
t.Require().True(true, "This should pass")
})
s.Run(t, "TestExample2", func(t provider.T) {
t.Epic("Example")
t.Feature("Test Suite 1")
t.Title("Test Example 2")
// 更多测试逻辑
})
}
// 示例测试套件2
type MyTestSuite2 struct {
suite.Suite
}
func (s *MyTestSuite2) TestAll(t *testing.T) {
s.Run(t, "TestSuite2_Example1", func(t provider.T) {
t.Epic("Example")
t.Feature("Test Suite 2")
t.Title("Another Test Example")
// 测试逻辑
})
}
func main() {
// 创建测试运行器
runner := NewCustomTestRunner()
// 添加你的10个测试套件
runner.AddSuite(&MyTestSuite1{})
runner.AddSuite(&MyTestSuite2{})
// 继续添加其他8个测试套件...
// 设置Allure报告目录
os.Setenv("ALLURE_OUTPUT_DIR", "./allure-results")
fmt.Println("Starting test execution...")
startTime := time.Now()
// 运行所有测试
allPassed := runner.RunAll()
duration := time.Since(startTime)
fmt.Printf("Test execution completed in %v\n", duration)
if allPassed {
fmt.Println("All test suites passed!")
os.Exit(0)
} else {
fmt.Println("Some test suites failed!")
os.Exit(1)
}
}
如果你需要更细粒度的控制,这里还有一个使用testing.MainStart的替代方案:
package main
import (
"flag"
"fmt"
"os"
"testing"
)
var testSuites = []testing.InternalTest{
{
Name: "TestSuite1",
F: func(t *testing.T) {
// 调用你的第一个测试套件
suite1 := &MyTestSuite1{}
suite1.TestAll(t)
},
},
{
Name: "TestSuite2",
F: func(t *testing.T) {
// 调用你的第二个测试套件
suite2 := &MyTestSuite2{}
suite2.TestAll(t)
},
},
// 添加更多测试套件...
}
func main() {
flag.Parse()
// 使用testing包的内置运行器
m := testing.MainStart(testDeps{}, testSuites, nil, nil, nil)
exitCode := m.Run()
fmt.Printf("Exit code: %d\n", exitCode)
os.Exit(exitCode)
}
// 实现testing.testDeps接口
type testDeps struct{}
func (d testDeps) MatchString(pat, str string) (bool, error) {
return false, nil
}
func (d testDeps) StartCPUProfile(interface{}) error {
return nil
}
func (d testDeps) StopCPUProfile() {}
func (d testDeps) WriteProfileTo(string, interface{}, interface{}) error {
return nil
}
func (d testDeps) ImportPath() string {
return ""
}
func (d testDeps) StartTestLog(interface{}) {}
func (d testDeps) StopTestLog() error {
return nil
}
对于allure-go的集成,确保你的测试套件正确实现了测试方法:
// 在你的测试套件包中
package mytests
import (
"testing"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)
type YourTestSuite struct {
suite.Suite
}
func (s *YourTestSuite) TestAll(t *testing.T) {
// 使用Allure的Run方法执行测试
s.Run(t, "YourTestName", func(t provider.T) {
t.Epic("YourEpic")
t.Feature("YourFeature")
t.Title("Test Title")
// 测试步骤
t.WithNewStep("Step 1", func(ctx provider.StepCtx) {
// 测试逻辑
t.Require().Equal(1, 1, "Values should be equal")
})
})
}
这种方法让你完全控制测试执行流程,可以集成到CI/CD流水线中,或者与其他系统进行集成。

