Unit test mode identification in golang - go

I am building unit testing of the application that uses os.Exit(1), once os.Exit(1) executes remaining test file are skipped with go test,
I am thinking about suppressing os.Exit during the unit test execution only. I wonder how I can determine that app has been bootstrap from go test runner?

You will find various ways to unit test method with os.Exit() in "Testing os.Exit scenarios in Go with coverage information (coveralls.io/Goveralls)".
It uses a function which is:
os.Exit() when you are not testing
var osExit = os.Exit
and "yourOsExit" when you are testing.
func TestCrasher(t *testing.T) {
// Save current function and restore at the end:
oldOsExit := osExit
defer func() { osExit = oldOsExit }()
osExit = myExit

Related

Trying to run tests in parallel with golang testify/suite fails

I have several tests using testify/suite package and I execute them in parallel as follows
type IntegrationSuite struct {
suite.Suite
}
func TestIntegrationSuite(t *testing.T) {
suite.Run(t, &IntegrationSuite{})
}
func (is *IntegrationSuite) TestSomething() {
is.T().Log("\tIntegration Testing something")
for i := range myTestTable {
i := i
is.T().Run("Testing "+myTestTable[i].scenarioName, func(_ *testing.T) {
is.T().Parallel()
...
func (is *IntegrationSuite) TestSomethingElse() {
is.T().Log("\tIntegration Testing something else")
for i := range myOtherTestTable {
i := i
is.T().Run("Testing "+myOtherTestTable[i].scenarioName, func(_ *testing.T) {
is.T().Parallel()
...
})
However this panics with
panic: testing: t.Parallel called multiple times [recovered]
panic: testing: t.Parallel called multiple times
How can one leverage parallelism with the specific package?
You're calling t.Parallel() on the wrong instance of testing.T.
You're spinning up multiple subtests using:
is.T().Run("Testing "+myOtherTestTable[i].scenarioName, func(_ *testing.T) {...}
But instead of marking the subtest as parallel, you're marking the outer parent test as parallel for every subtest you start:
is.T().Parallel() // marks outer test as parallel
Instead, bind the subtest func's testing.T param to a variable and call Parallel on the subtest:
is.T().Run("Testing "+myOtherTestTable[i].scenarioName, func(t *testing.T) {
t.Parallel() // this is the subtest's T instance
// test code
})
This marks all subtests as parallel within the parent test. If you also want to mark the parent test as parallel with other tests in the package, call is.T().Parallel() once at the beginning of TestSomethingElse (not within the subtest)
For more details on parallelism of subtests, see: Control of Parallelism
Please note that the testify suite is currently not "thread safe" and therefore does not support concurrency. There are cases in which tests pass successfully even though they should fail.
Please find the current status as well the reported issues here: https://github.com/stretchr/testify/issues/187

Go Test - empty coverage file

I have a go project, test directory contains a single sample test file.
Few Functions of the test file are
func TestMain(m *testing.M) {
setup()
code := m.Run()
shutdown()
os.Exit(code)
}
func TestUserLogin(t *testing.T) {
//sample code to make api call and validate response
}
func setup() {
//start service
}
func shutdown() {
//stop service
}
I want to see/generate a coverage report. The following command is being used to run tests:
go test -coverprofile=coverage.out
Output on terminal is
PASS
coverage: 100.0% of statements
coverage.out is getting generated but it consists of only single line
mode: set
coverage.out should have information about the files, lines, etc.
Anything that I am doing wrong here?
test directory contains a single sample test file
Here it is, Go coverage does not work if your *_test.go files are not in the same directory a.k.a they have been put in another folder.

fail unit tests if coverage is below certain percentage

I make a makefile that executes go test -cover. Is it possible to fail the make unit_tests command if coverage is below X? How would I do that?
You can use TestMain in your test to do that. TestMain can act as a custom entry point to tests, and then you can invoke testing.Coverage() to get access to the coverage stats.
So for example, if you want to fail at anything below 80%, you could add this to one of your package's test files:
func TestMain(m *testing.M) {
// call flag.Parse() here if TestMain uses flags
rc := m.Run()
// rc 0 means we've passed,
// and CoverMode will be non empty if run with -cover
if rc == 0 && testing.CoverMode() != "" {
c := testing.Coverage()
if c < 0.8 {
fmt.Println("Tests passed but coverage failed at", c)
rc = -1
}
}
os.Exit(rc)
}
Then go test -cover will call this entry point and you'll fail:
PASS
coverage: 63.0% of statements
Tests passed but coverage failed at 0.5862068965517241
exit status 255
FAIL github.com/xxxx/xxx 0.026s
Notice that the number that testing.Coverage() returns is lower than what the test reports. I've looked at the code and the function calculates its coverage differently than the test's internal reporting. I'm not sure which is more "correct".

How can stdout be captured or suppressed for Go(lang) testing?

How can stdout be captured or suppressed for Go testing?
I am trying to teach myself go(lang) testing. In the code below, myshow.LoadPath prints lots of information to stdout (which is a normal side effect). It does however make for very noisy output when I run "go test" Is there a way to suppress or capture stdout?
For comparison, I'm thinking about something like this from the python world. http://pytest.org/latest/capture.html#captures
package slideshow_test
import (
"os"
"testing"
"github.com/golliher/go-hpf/slideshow"
)
func setupTest() {
myshow := slideshow.Slideshow{Name: "This is my show"}
myshow.LoadPath("..")
}
func TestStub(t *testing.T) {
if true == false {
t.Fail()
}
}
func TestMain(m *testing.M) {
setupTest()
os.Exit(m.Run())
}
os.Stdout which is used by the fmt.Printf and others is just a variable. So you can overwrite it at any time and restore it back when necessary. https://golang.org/pkg/os/#pkg-variables
To suppress the output during the test I use the following code. I fixes output as well as logging. After test is done it resets the output streams.
func TestStartStowWrongCommand(t *testing.T) {
defer quiet()()
...
}
func quiet() func() {
null, _ := os.Open(os.DevNull)
sout := os.Stdout
serr := os.Stderr
os.Stdout = null
os.Stderr = null
log.SetOutput(null)
return func() {
defer null.Close()
os.Stdout = sout
os.Stderr = serr
log.SetOutput(os.Stderr)
}
}
The output can be suppressed
by running the tests with go test .:
$ go help test
Go test runs in two different modes: local
directory mode when invoked with no package arguments (for example,
'go test'), and package list mode when invoked with package arguments
(for example 'go test math', 'go test ./...', and even 'go test .').
In local directory mode, go test compiles and tests the package
sources found in the current directory and then runs the resulting
test binary. In this mode, caching (discussed below) is disabled.
After the package test finishes, go test prints a summary line showing
the test status ('ok' or 'FAIL'), package name, and elapsed time.
In 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. 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.
Not exactly what you are asking for but still might be helpful.
You can use t.Log (http://golang.org/pkg/testing/#T.Log) and t.Logf (http://golang.org/pkg/testing/#T.Logf) methods in the test method. The output will be printed only if the test fails or the -test.v flag is set.
I also would suggest to use log package to print to the console in myshow.LoadPath. Then you can disable (or capture) the output in the test by setting custom writer using log.SetOutput

golang testing method after each test: undefined: testing.M

I am trying to repeat example from golang testing
package main
import (
"testing"
)
func TestSomeTest(t *testing.T) {}
func TestMain(m *testing.M) { // cleaning after each test}
I want TestMain function to run after every test.
Running command go test
And the compiler says
./testingM_test.go:9: undefined: testing.M
So how to clean after executing every test?
Check you go version output: this is for go 1.4+ only.
The testing package has a new facility to provide more control over running a set of tests. If the test code contains a function
func TestMain(m *testing.M)
that function will be called instead of running the tests directly.
The M struct contains methods to access and run the tests.
You can see that feature used here:
The introduction of TestMain() made it possible to run these migrations only once. The code now looks like this:
func TestSomeFeature(t *testing.T) {
defer models.TestDBManager.Reset()
// Do the tests
}
func TestMain(m *testing.M) {
models.TestDBManager.Enter()
// os.Exit() does not respect defer statements
ret := m.Run()
models.TestDBManager.Exit()
os.Exit(ret)
}
While each test must still clean up after itself, that only involves restoring the initial data, which is way faster than doing the schema migrations.

Resources