Home > Mobile >  Can I output log messages from TestMain?
Can I output log messages from TestMain?

Time:03-19

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
$ 

CodePudding user response:

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.

CodePudding user response:

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)
  • Related