mirror of https://github.com/stretchr/testify.git
Allow custom test name formats
When using suites, test names were just the raw suite method name, but that's often not detailed enough to know what the problem is. This commit adds the ability to pass a custom name format using certain formatting marks (sort of similar to templating strings) to include the name of the function that called Run or NamedRun, the name of the suite's type, and/or the name of the method.pull/115/head
parent
8bb32e75f4
commit
4ecf7fc077
|
@ -6,12 +6,38 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var matchMethod = flag.String("m", "", "regular expression to select tests of the suite to run")
|
const (
|
||||||
|
testPattern = "^Test"
|
||||||
|
defaultFormat = "{method}"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
matchMethod = flag.String("m", "", "Run only those test methods matching the regular expression.")
|
||||||
|
format = flag.String("nameformat", "",
|
||||||
|
"The format to use for test name output. Use {function} for the test function name, "+
|
||||||
|
"{suite} for the suite type name, and {method} for the test method name. Overrides "+
|
||||||
|
"formatting set by NamedRun.")
|
||||||
|
)
|
||||||
|
|
||||||
|
type testIdentifier struct {
|
||||||
|
function string
|
||||||
|
suite string
|
||||||
|
method string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t testIdentifier) Name(format string) string {
|
||||||
|
name := strings.Replace(format, "{function}", t.function, -1)
|
||||||
|
name = strings.Replace(name, "{suite}", t.suite, -1)
|
||||||
|
name = strings.Replace(name, "{method}", t.method, -1)
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
// Suite is a basic testing suite with methods for storing and
|
// Suite is a basic testing suite with methods for storing and
|
||||||
// retrieving the current *testing.T context.
|
// retrieving the current *testing.T context.
|
||||||
|
@ -32,8 +58,44 @@ func (suite *Suite) SetT(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run takes a testing suite and runs all of the tests attached
|
// Run takes a testing suite and runs all of the tests attached
|
||||||
// to it.
|
// to it. For legacy reasons, Run uses a default test name format
|
||||||
|
// of "{method}", which only prints out the test method name. See
|
||||||
|
// NamedRun for a version of Run that accepts other format strings
|
||||||
|
// for the test name in testing output.
|
||||||
func Run(t *testing.T, suite TestingSuite) {
|
func Run(t *testing.T, suite TestingSuite) {
|
||||||
|
run("", t, suite)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamedRun performs a test run the same as Run, but with a different
|
||||||
|
// test name format. Pass a pattern to use as your test names for
|
||||||
|
// nameFormat. The following patterns will be replaced by details
|
||||||
|
// about the current test:
|
||||||
|
//
|
||||||
|
// * "{function}": The name of the function that called NamedRun.
|
||||||
|
// * "{suite}": The name of the testing suite's underlying type.
|
||||||
|
// * "{method}": The name of the test method.
|
||||||
|
//
|
||||||
|
// Be aware that the test flag "nameformat" will override nameFormat
|
||||||
|
// globally.
|
||||||
|
func NamedRun(nameFormat string, t *testing.T, suite TestingSuite) {
|
||||||
|
run(nameFormat, t, suite)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run is used to ensure that Run and NamedRun (and any other suite
|
||||||
|
// running functions) are at the same calling stack depth.
|
||||||
|
func run(nameFormat string, t *testing.T, suite TestingSuite) {
|
||||||
|
if nameFormat == "" {
|
||||||
|
nameFormat = defaultFormat
|
||||||
|
}
|
||||||
|
if *format != "" {
|
||||||
|
nameFormat = *format
|
||||||
|
}
|
||||||
|
id := testIdentifier{}
|
||||||
|
if callPC, _, _, ok := runtime.Caller(2); ok {
|
||||||
|
id.function = runtime.FuncForPC(callPC).Name()
|
||||||
|
id.function = id.function[strings.LastIndex(id.function, ".")+1:]
|
||||||
|
}
|
||||||
|
|
||||||
suite.SetT(t)
|
suite.SetT(t)
|
||||||
|
|
||||||
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
||||||
|
@ -45,7 +107,13 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
methodFinder := reflect.TypeOf(suite)
|
suiteType := reflect.TypeOf(suite)
|
||||||
|
methodFinder := suiteType
|
||||||
|
if suiteType.Kind() == reflect.Ptr {
|
||||||
|
suiteType = suiteType.Elem()
|
||||||
|
}
|
||||||
|
id.suite = suiteType.Name()
|
||||||
|
|
||||||
tests := []testing.InternalTest{}
|
tests := []testing.InternalTest{}
|
||||||
for index := 0; index < methodFinder.NumMethod(); index++ {
|
for index := 0; index < methodFinder.NumMethod(); index++ {
|
||||||
method := methodFinder.Method(index)
|
method := methodFinder.Method(index)
|
||||||
|
@ -55,8 +123,9 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
|
id.method = method.Name
|
||||||
test := testing.InternalTest{
|
test := testing.InternalTest{
|
||||||
Name: method.Name,
|
Name: id.Name(nameFormat),
|
||||||
F: func(t *testing.T) {
|
F: func(t *testing.T) {
|
||||||
parentT := suite.T()
|
parentT := suite.T()
|
||||||
suite.SetT(t)
|
suite.SetT(t)
|
||||||
|
@ -82,10 +151,10 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtering method according to set regular expression
|
// methodFilter filters method names similar to `go test -run regexp`. Note
|
||||||
// specified command-line argument -m
|
// that methods must match testPattern prior to matching the passed in regexp.
|
||||||
func methodFilter(name string) (bool, error) {
|
func methodFilter(name string) (bool, error) {
|
||||||
if ok, _ := regexp.MatchString("^Test", name); !ok {
|
if ok, _ := regexp.MatchString(testPattern, name); !ok {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return regexp.MatchString(*matchMethod, name)
|
return regexp.MatchString(*matchMethod, name)
|
||||||
|
|
Loading…
Reference in New Issue