我可以从 TestMain 输出日志消息吗?

发布于 2025-01-14 23:10:46 字数 840 浏览 3 评论 0原文

我想编写一个集成测试来测试向数据库写入数据和从数据库读取数据。为此,我需要第一个测试函数来连接并准备测试数据库;如果成功,则运行其他测试,然后对其进行查询。

因此,我实现了一个 TestMain(m *testing.M),它创建一个数据库并在其上运行迁移,如果没有错误,我会运行 m.Run()

但它没有像 testing.T 那样的任何 m.Printm.Fatal 方法。如果我尝试使用 log.Print() 记录某些内容,它不会获得输出(可能是因为没有测试可以被正确标记为失败)。

我不喜欢使用常规测试功能创建数据库的原因是,常规测试当然不能阻止其他测试的运行,因此该文件中的所有其他测试都将运行并困扰输出消息,因为他们都会失败。

那么我如何从 TestMain 中注销一些内容呢?我的 TestMain 仍然可能以多种方式失败,我想在输出中看到它是什么。

显示 TestMain 的输出未显示的示例:

$ ls
go.mod      main_test.go
$ cat go.mod
module App

go 1.16
$ cat main_test.go 
package main

import (
    "testing"
    "log"
)

func TestMain(m *testing.M) {
    log.Print("hello")
}
$ go test ./.
ok      App 0.147s
$ 

I want to write an integration test which tests writing and reading data to and from a database. In order to do this, I need my first test function to connect and prepare a test database; and if that is a success, let the other tests run, which will then be doing queries on it.

So I implemented a TestMain(m *testing.M) which creates a database and runs migrations on it, and if there's no errors, I run m.Run().

But it doesn't have any m.Print or m.Fatal methods like testing.T does. And if I try to log something with log.Print(), it doesn't get output (probably because no testing could have been properly marked as failing).

And the reason why I don't like the creation of the database with a regular test function, is because a regular test of course cannot stop other tests from running, so all my other tests from that file will run and plague the output messages, since they will all fail.

So how do I log something out from TestMain? My TestMain can still fail in multiple ways, and i would like to see in the output what it was.

Example to show TestMain's output not being displayed:

$ ls
go.mod      main_test.go
$ cat go.mod
module App

go 1.16
$ cat main_test.go 
package main

import (
    "testing"
    "log"
)

func TestMain(m *testing.M) {
    log.Print("hello")
}
$ go test ./.
ok      App 0.147s
$ 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你好,陌生人 2025-01-21 23:10:46

如果测试以非零代码退出,则使用 log.Print() 打印的消息似乎会显示,因此这种情况最好通过在日志行之后以非零代码退出来解决,例如所以:

log.Print("setup of database has failed")
os.Exit(1)

It seems that messages printed with log.Print() will display if the test exits with a non-zero code, so this situation is best solved by exiting with non-zero right after the log line, like so:

log.Print("setup of database has failed")
os.Exit(1)
棒棒糖 2025-01-21 23:10:46

您需要 -v 标志:

go test -v .

注意:. 相当于 ./.

如果您想在所有子目录上运行测试,请使用 < code>./... 就像这样:

go test -v ./...

这是为什么?由于您正在所谓的包列表模式(即 ./.)中运行测试 - 来自 go help test 中的文档:

在此(包列表)模式下,go test 编译并测试列出的每个包
在命令行上。如果包测试通过,则 go test 仅打印
最后的“ok”总结行。如果包测试失败,则 go test 打印
完整的测试输出。

这是您注意到的行为。进一步阅读:

...如果使用 -bench 或 -v 标志调用,则转到
即使通过了包测试,测试也会打印完整的输出,以便
显示请求的基准测试结果或详细日志记录。


注意: go test 单独(即没有包列表)将允许从 TestMain 输出日志记录,如 log.Print


编辑
以下是我通常为测试进行飞行前设置的方式:

var testDB     *pgxpool.Pool // all tests should use this

func createDBconn() (*pgxpool.Pool, error) {
    // read ENV VARs - establish connection
    // ...
    return dbconn, nil
}

func TestMain(m *testing.M) {
    var err error
    
    testDB, err = createDBconn()
    if err != nil {
        log.Fatal(err)
    }

    // call flag.Parse() here if TestMain uses flags
    os.Exit(m.Run())
}

如果任何准备失败,则 log.Fatal 确保记录原因并记录原因。程序终止。

You need the -v flag:

go test -v .

Note: . is equivalent to ./.

If you want to run tests on all sub-directories use ./... like so:

go test -v ./...

Why is this? Since you are running tests in what's call package list mode (i.e. ./.) - from the docs in go help test:

In this (package list) mode, go test compiles and tests each of the packages listed
on the command line. If a package test passes, go test prints only the
final 'ok' summary line. If a package test fails, go test prints the
full test output.

This is the behavior you have noted. Reading further:

... If invoked with the -bench or -v flag, go
test prints the full output even for passing package tests, in order
to display the requested benchmark results or verbose logging.


Note: go test alone (i.e. no package list) will allow output logging from TestMain like log.Print.


EDIT
here's how I typically do pre-flight setup for my tests:

var testDB     *pgxpool.Pool // all tests should use this

func createDBconn() (*pgxpool.Pool, error) {
    // read ENV VARs - establish connection
    // ...
    return dbconn, nil
}

func TestMain(m *testing.M) {
    var err error
    
    testDB, err = createDBconn()
    if err != nil {
        log.Fatal(err)
    }

    // call flag.Parse() here if TestMain uses flags
    os.Exit(m.Run())
}

if any of the prep fails, then log.Fatal ensures the reason is logged & the program terminates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文