所有测试的TestMain函数?

huangapple go评论69阅读模式
英文:

TestMain for all tests?

问题

我有一个相当大的项目,其中有许多集成测试分散在不同的包中。我正在使用构建标签来区分单元测试、集成测试和端到端测试。

在运行集成测试和端到端测试之前,我需要进行一些设置,所以我在根目录下的main_test.go文件中放置了一个TestMain函数。它非常简单:

//go:build integration || e2e
// +build integration e2e

package test

import (
  ...
)

func TestMain(m *testing.M) {
  if err := setup(); err != nil {
    os.Exit(1)
  }

  exitCode := m.Run()

  if err := tearDown(); err != nil {
    os.Exit(1)
  }

  os.Exit(exitCode)

}

func setup() error {
  // 在这里进行设置...
  return nil
}

func tearDown() error {
  // 在这里进行清理...
  return nil
}

然而,当我运行测试时:

$ go test -v --tags=integration ./...

testing: warning: no tests to run
PASS

# 所有子目录的测试现在都运行并失败了...

我真的不想在每个需要它的包中编写一个TestMain,希望我只需要在根目录中写一个就可以了。你有什么解决方案可以建议吗?谢谢。

我能想到的唯一替代方案是在代码之外设置一切,然后运行集成测试。也许可以编写一个进行设置并调用$ go test的Shell脚本?

英文:

I have a fairly large project with many integration tests sprinkled throughout different packages. I'm using build tags to separate unit, integration and e2e tests.

I need to do some setup before running my integration and e2e tests, so I put a TestMain function in a main_test.go file in the root directory. It's pretty simple:

//go:build integration || e2e
// +build integration e2e

package test

import (
  ...
)

func TestMain(m *testing.M) {
  if err := setup(); err != nil {
    os.Exit(1)
  }

  exitCode := m.Run()

  if err := tearDown(); err != nil {
    os.Exit(1)
  }

  os.Exit(exitCode)

}

func setup() error {
  // setup stuff here...
  return nil
}

func tearDown() error {
  // tear down stuff here...
  return nil
}

However, when I run test:

$ go test -v --tags=integration ./...

testing: warning: no tests to run
PASS

# all of my subdirectory tests now run and fail...

I really don't want to write a TestMain in each package that requires it and was hoping I could just get away with one in the root. Is there any solution that you could suggest? Thanks.

The only alternative I can think of is setting up everything outside of code and then running the integration tests. Maybe some shell script that does setup and then calls $ go test?

答案1

得分: 2

go test ./... 命令会在后台为每个包编译一个测试二进制文件,并逐个运行它们。这也是为什么如果你尝试指定一个输出时会出现 cannot use -o flag with multiple packages 错误的原因。这也是为什么你主包中的代码不会影响到子包的原因。

所以唯一的解决方法是将所有的设置逻辑放在一个类似于 "setup" 的包中,并从所有的子包中调用共享的代码(我知道这是很多工作)。

英文:

The go test ./... command compiles a test binary for each package in the background and runs them one by one. This is also the reason you get a cannot use -o flag with multiple packages error if you attempt to specify an output. This is the reason code in your main package doesn't effect your sub packages.

So the only way to get this to work is to put all your setup logic in sort of "setup" package and call the shared code from all of your sub-packages(still a lot of work, I know).

答案2

得分: 1

尝试避免代码重复,我使用了一个函数来进行设置/拆卸并评估一个函数作为测试。

这个函数应该是这样的:

func WithTestSetup(t *testing.T, testFunction func()) {
    // 设置代码

    testFunction()

    // 拆卸代码
}

我使用t *testing.T参数来报告设置或拆卸中的错误,但它可以省略。

然后在你的测试中可以这样使用:

func TestFoo(t *testing.T) {
    WithTestSetup(
        t, func() {
            if err := Foo(); err != nil {
                t.Fatal(err)
            }
        },
    )
}

只需在需要的地方调用WithTestSetup,对我来说比在项目中添加一堆TestMain要容易。

英文:

Trying to avoid code repetition, I used a function that makes the setup/teardown and evaluates a function as a test.

The function should look like this

func WithTestSetup(t *testing.T, testFunction func()) {
    // setup code

    testFunction()

    // teardown code
}

I use the t *testing.T argument to report errors in setup or teardown, but it can be omitted.

Then in your tests you can make:

func TestFoo(t *testing.T) {
    WithTestSetup(
        t, func() {
            if err := Foo(); err != nil {
                t.Fatal(err)
            }
        },
    )
}

Just call WithTestSetup if needed, looks easier for me than add a bunch of TestMains on the project.

huangapple
  • 本文由 发表于 2021年12月17日 04:12:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/70385066.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定