Run tests programmatically in Go

Viewed 682

I have some tests that I'd like to run programmatically in Go. I'm trying to use testing.RunTests but it's raising a runtime error. I can't figure out what's wrong with the code either.

This is what it looks like:

package main

import (
    "testing"
)

func TestSomething(t *testing.T) {
    if false {
        t.Error("This is a mocked failed test")
    }
}

func main() {
    testing.RunTests(func(pat, str string) (bool, error) { return true, nil },
        []testing.InternalTest{
            {"Something", TestSomething}},
    )
}

Playground link: https://play.golang.org/p/BC5MG8WXYGD

The error I'm getting is:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4b5948]
2 Answers

First of all, running tests should be done via the go test command.

Certain types and functions exported in the testing package are for the testing framework, not for you. Quoting from testing.RunTests():

RunTests is an internal function but exported because it is cross-package; it is part of the implementation of the "go test" command.

It "had" to be exported because it predates "internal" packages.

There. You've been warned.

If you still want to do it, call testing.Main() instead of testing.RunTests().

For example:

func TestGood(t *testing.T) {
}

func TestBad(t *testing.T) {
    t.Error("This is a mocked failed test")
}

func main() {
    testing.Main(
        nil,
        []testing.InternalTest{
            {"Good", TestGood},
            {"Bad", TestBad},
        },
        nil, nil,
    )
}

Which will output (try it on the Go Playground):

--- FAIL: Bad (0.00s)
    prog.go:11: This is a mocked failed test
FAIL

If you want to capture the success of the testing, use the "newer" testing.MainStart() function.

First we need a helper type (which implements an unexported interface):

type testDeps struct{}

func (td testDeps) MatchString(pat, str string) (bool, error)   { return true, nil }
func (td testDeps) StartCPUProfile(w io.Writer) error           { return nil }
func (td testDeps) StopCPUProfile()                             {}
func (td testDeps) WriteProfileTo(string, io.Writer, int) error { return nil }
func (td testDeps) ImportPath() string                          { return "" }
func (td testDeps) StartTestLog(io.Writer)                      {}
func (td testDeps) StopTestLog() error                          { return nil }
func (td testDeps) SetPanicOnExit0(bool)                        {}

And now using it:

m := testing.MainStart(testDeps{},
    []testing.InternalTest{
        {"Good", TestGood},
        {"Bad", TestBad},
    },
    nil, nil,
)

result := m.Run()
fmt.Println(result)

Which outputs (try it on the Go Playground):

--- FAIL: Bad (0.00s)
    prog.go:13: This is a mocked failed test
FAIL
1

If all tests pass, result will be 0.

Related