mirror of https://github.com/stretchr/testify.git
Add stats to suites and tests
parent
cb23521296
commit
e8910bb335
|
@ -1,6 +1,8 @@
|
||||||
package suite
|
package suite
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
// TestingSuite can store and return the current *testing.T context
|
// TestingSuite can store and return the current *testing.T context
|
||||||
// generated by 'go test'.
|
// generated by 'go test'.
|
||||||
|
@ -44,3 +46,8 @@ type BeforeTest interface {
|
||||||
type AfterTest interface {
|
type AfterTest interface {
|
||||||
AfterTest(suiteName, testName string)
|
AfterTest(suiteName, testName string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithStats is a suite which measures some stats for its tests.
|
||||||
|
type WithStats interface {
|
||||||
|
HandleStats(suiteName string, stats *SuiteInformation)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package suite
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// SuiteInformation stats stores stats for the whole suite execution.
|
||||||
|
type SuiteInformation struct {
|
||||||
|
Start, End time.Time
|
||||||
|
Passed bool
|
||||||
|
TestStats map[string]*TestInformation
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInformation stores information about the execution of each test.
|
||||||
|
type TestInformation struct {
|
||||||
|
TestName string
|
||||||
|
Start, End time.Time
|
||||||
|
Passed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSuiteInformation() *SuiteInformation {
|
||||||
|
testStats := make(map[string]*TestInformation)
|
||||||
|
|
||||||
|
return &SuiteInformation{
|
||||||
|
TestStats: testStats,
|
||||||
|
Passed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SuiteInformation) start(testName string) {
|
||||||
|
s.TestStats[testName] = &TestInformation{
|
||||||
|
TestName: testName,
|
||||||
|
Start: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SuiteInformation) end(testName string, passed bool) {
|
||||||
|
s.TestStats[testName].End = time.Now()
|
||||||
|
s.TestStats[testName].Passed = passed
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -87,6 +88,14 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
|
|
||||||
suiteSetupDone := false
|
suiteSetupDone := false
|
||||||
|
|
||||||
|
var (
|
||||||
|
stats *SuiteInformation
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, measureStats := suite.(WithStats); measureStats {
|
||||||
|
stats = newSuiteInformation()
|
||||||
|
}
|
||||||
|
|
||||||
methodFinder := reflect.TypeOf(suite)
|
methodFinder := reflect.TypeOf(suite)
|
||||||
tests := []testing.InternalTest{}
|
tests := []testing.InternalTest{}
|
||||||
for index := 0; index < methodFinder.NumMethod(); index++ {
|
for index := 0; index < methodFinder.NumMethod(); index++ {
|
||||||
|
@ -96,21 +105,36 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
|
fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suiteName := methodFinder.Elem().Name()
|
||||||
|
|
||||||
if !suiteSetupDone {
|
if !suiteSetupDone {
|
||||||
|
if stats != nil {
|
||||||
|
stats.Start = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
||||||
setupAllSuite.SetupSuite()
|
setupAllSuite.SetupSuite()
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
|
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
|
||||||
testsSync.Wait()
|
testsSync.Wait()
|
||||||
tearDownAllSuite.TearDownSuite()
|
tearDownAllSuite.TearDownSuite()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if suiteWithStats, measureStats := suite.(WithStats); measureStats {
|
||||||
|
stats.End = time.Now()
|
||||||
|
suiteWithStats.HandleStats(suiteName, stats)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
suiteSetupDone = true
|
suiteSetupDone = true
|
||||||
}
|
}
|
||||||
|
|
||||||
test := testing.InternalTest{
|
test := testing.InternalTest{
|
||||||
Name: method.Name,
|
Name: method.Name,
|
||||||
F: func(t *testing.T) {
|
F: func(t *testing.T) {
|
||||||
|
@ -122,16 +146,34 @@ func Run(t *testing.T, suite TestingSuite) {
|
||||||
if setupTestSuite, ok := suite.(SetupTestSuite); ok {
|
if setupTestSuite, ok := suite.(SetupTestSuite); ok {
|
||||||
setupTestSuite.SetupTest()
|
setupTestSuite.SetupTest()
|
||||||
}
|
}
|
||||||
|
|
||||||
if beforeTestSuite, ok := suite.(BeforeTest); ok {
|
if beforeTestSuite, ok := suite.(BeforeTest); ok {
|
||||||
beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
|
beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stats != nil {
|
||||||
|
stats.start(method.Name)
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if afterTestSuite, ok := suite.(AfterTest); ok {
|
if stats != nil {
|
||||||
afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name)
|
passed := !t.Failed()
|
||||||
|
|
||||||
|
stats.end(method.Name, passed)
|
||||||
|
|
||||||
|
if !passed {
|
||||||
|
stats.Passed = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if afterTestSuite, ok := suite.(AfterTest); ok {
|
||||||
|
afterTestSuite.AfterTest(suiteName, method.Name)
|
||||||
|
}
|
||||||
|
|
||||||
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
|
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
|
||||||
tearDownTestSuite.TearDownTest()
|
tearDownTestSuite.TearDownTest()
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.SetT(parentT)
|
suite.SetT(parentT)
|
||||||
}()
|
}()
|
||||||
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
|
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
|
||||||
|
|
|
@ -482,3 +482,33 @@ func (s *CallOrderSuite) Test_A() {
|
||||||
func (s *CallOrderSuite) Test_B() {
|
func (s *CallOrderSuite) Test_B() {
|
||||||
s.call("Test B")
|
s.call("Test B")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type suiteWithStats struct {
|
||||||
|
Suite
|
||||||
|
wasCalled bool
|
||||||
|
stats *SuiteInformation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suiteWithStats) HandleStats(suiteName string, stats *SuiteInformation) {
|
||||||
|
s.wasCalled = true
|
||||||
|
s.stats = stats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suiteWithStats) TestSomething() {
|
||||||
|
s.Equal(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuiteWithStats(t *testing.T) {
|
||||||
|
suiteWithStats := new(suiteWithStats)
|
||||||
|
Run(t, suiteWithStats)
|
||||||
|
|
||||||
|
assert.True(t, suiteWithStats.wasCalled)
|
||||||
|
assert.NotZero(t, suiteWithStats.stats.Start)
|
||||||
|
assert.NotZero(t, suiteWithStats.stats.End)
|
||||||
|
assert.True(t, suiteWithStats.stats.Passed)
|
||||||
|
|
||||||
|
testStats := suiteWithStats.stats.TestStats["TestSomething"]
|
||||||
|
assert.NotZero(t, testStats.Start)
|
||||||
|
assert.NotZero(t, testStats.End)
|
||||||
|
assert.True(t, testStats.Passed)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue