diff --git a/suite/suite.go b/suite/suite.go index d62c743a2..790eaa3e4 100644 --- a/suite/suite.go +++ b/suite/suite.go @@ -63,6 +63,19 @@ func failOnPanic(t *testing.T) { } } +// Run provides suite functionality around golang subtests. It should be +// called in place of t.Run(name, func(t *testing.T)) in test suite code. +// The passed-in func will be executed as a subtest with a fresh instance of t. +// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName. +func (suite *Suite) Run(name string, subtest func()) { + oldT := suite.T() + defer suite.SetT(oldT) + oldT.Run(name, func(t *testing.T) { + suite.SetT(t) + subtest() + }) +} + // Run takes a testing suite and runs all of the tests attached // to it. func Run(t *testing.T, suite TestingSuite) { diff --git a/suite/suite_test.go b/suite/suite_test.go index 1c69d5472..6dfba08cd 100644 --- a/suite/suite_test.go +++ b/suite/suite_test.go @@ -152,6 +152,7 @@ type SuiteTester struct { TearDownTestRunCount int TestOneRunCount int TestTwoRunCount int + TestSubtestRunCount int NonTestMethodRunCount int SuiteNameBefore []string @@ -246,6 +247,27 @@ func (suite *SuiteTester) NonTestMethod() { suite.NonTestMethodRunCount++ } +func (suite *SuiteTester) TestSubtest() { + suite.TestSubtestRunCount++ + + for _, t := range []struct { + testName string + }{ + {"first"}, + {"second"}, + } { + suiteT := suite.T() + suite.Run(t.testName, func() { + // We should get a different *testing.T for subtests, so that + // go test recognizes them as proper subtests for output formatting + // and running individual subtests + subTestT := suite.T() + suite.NotEqual(subTestT, suiteT) + }) + suite.Equal(suiteT, suite.T()) + } +} + // TestRunSuite will be run by the 'go test' command, so within it, we // can run our suite using the Run(*testing.T, TestingSuite) function. func TestRunSuite(t *testing.T) { @@ -261,18 +283,20 @@ func TestRunSuite(t *testing.T) { assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) - assert.Equal(t, len(suiteTester.SuiteNameAfter), 3) - assert.Equal(t, len(suiteTester.SuiteNameBefore), 3) - assert.Equal(t, len(suiteTester.TestNameAfter), 3) - assert.Equal(t, len(suiteTester.TestNameBefore), 3) + assert.Equal(t, len(suiteTester.SuiteNameAfter), 4) + assert.Equal(t, len(suiteTester.SuiteNameBefore), 4) + assert.Equal(t, len(suiteTester.TestNameAfter), 4) + assert.Equal(t, len(suiteTester.TestNameBefore), 4) assert.Contains(t, suiteTester.TestNameAfter, "TestOne") assert.Contains(t, suiteTester.TestNameAfter, "TestTwo") assert.Contains(t, suiteTester.TestNameAfter, "TestSkip") + assert.Contains(t, suiteTester.TestNameAfter, "TestSubtest") assert.Contains(t, suiteTester.TestNameBefore, "TestOne") assert.Contains(t, suiteTester.TestNameBefore, "TestTwo") assert.Contains(t, suiteTester.TestNameBefore, "TestSkip") + assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest") for _, suiteName := range suiteTester.SuiteNameAfter { assert.Equal(t, "SuiteTester", suiteName) @@ -290,15 +314,16 @@ func TestRunSuite(t *testing.T) { assert.False(t, when.IsZero()) } - // There are three test methods (TestOne, TestTwo, and TestSkip), so + // There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so // the SetupTest and TearDownTest methods (which should be run once for - // each test) should have been run three times. - assert.Equal(t, suiteTester.SetupTestRunCount, 3) - assert.Equal(t, suiteTester.TearDownTestRunCount, 3) + // each test) should have been run four times. + assert.Equal(t, suiteTester.SetupTestRunCount, 4) + assert.Equal(t, suiteTester.TearDownTestRunCount, 4) // Each test should have been run once. assert.Equal(t, suiteTester.TestOneRunCount, 1) assert.Equal(t, suiteTester.TestTwoRunCount, 1) + assert.Equal(t, suiteTester.TestSubtestRunCount, 1) // Methods that don't match the test method identifier shouldn't // have been run at all.