Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suite: Support for BeforeSubTest and AfterSubTest methods #1363

Open
aliml92 opened this issue Mar 23, 2023 · 2 comments
Open

suite: Support for BeforeSubTest and AfterSubTest methods #1363

aliml92 opened this issue Mar 23, 2023 · 2 comments
Labels
enhancement pkg-suite Change related to package testify/suite

Comments

@aliml92
Copy link

aliml92 commented Mar 23, 2023

Would it be okay if the suite package has methods like below?

func (s *HandlerTestSuite) BeforeSubTest(suiteName, testName, subTestName string) {
	fmt.Println("BeforeSubTest()", suiteName, testName, subTestName)
}

func (s *HandlerTestSuite) AfterSubTest(suiteName, testName, subTestName string) {
	fmt.Println("AfterSubTest()", suiteName, testName, subTestName)
}
@aliml92
Copy link
Author

aliml92 commented Mar 23, 2023

We have this function in suite.go

// 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()) bool {
	oldT := suite.T()

	if setupSubTest, ok := suite.s.(SetupSubTest); ok {
		setupSubTest.SetupSubTest()
	}

	defer func() {
		suite.SetT(oldT)
		if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
			tearDownSubTest.TearDownSubTest()
		}
	}()

	return oldT.Run(name, func(t *testing.T) {
		suite.SetT(t)
		subtest()
	})
}

I changed it like the following:

// 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()) bool {
	oldT := suite.T()
	var (
		suiteName string
		parentName string
	)
	n := strings.Split(suite.s.T().Name(), "/")
	if len(n) > 1 {
		suiteName, parentName = n[0], n[1]
	}

	if setupSubTest, ok := suite.s.(SetupSubTest); ok {
		setupSubTest.SetupSubTest()
	}

	if beforeSubTest, ok := suite.s.(BeforeSubTest); ok {
		beforeSubTest.BeforeSubTest(suiteName, parentName, name)
	}


	defer func() {
		suite.SetT(oldT)
		if afterSubTest, ok := suite.s.(AfterSubTest); ok {
			afterSubTest.AfterSubTest(suiteName, parentName, name)
		}
		if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
			tearDownSubTest.TearDownSubTest()
		}
	}()

	return oldT.Run(name, func(t *testing.T) {
		suite.SetT(t)
		subtest()
	})
}

in interfaces.go

// BeforeSubTest has a function to be executed right before the sub-test
// starts and receives the suite, test and sub-test names as input
type BeforeSubTest interface {
	BeforeSubTest(suiteName, testName, subTestName string)
}

// AfterSubTest has a function to be executed right after the sub-test
// finishes and receives the suite, test and sub-test names as input
type AfterSubTest interface {
	AfterSubTest(suiteName, testName, subTestName string)
}

Is it viable to modify the code?

@mach6
Copy link

mach6 commented Mar 28, 2023

+1 for this proposal.

It would be nice to be able to get the subtest name in a Before or After func.. The current SetupSubTest and TearDownSubTest funcs do not satisfy this need.


@aliml92 I'd suggest changing

	if len(n) > 1 {
		suiteName, parentName = n[0], n[1]
	}

to

	if len(n) > 1 {
		suiteName, parentName = n[0], strings.Join(n[1:len(n)], "/")
	}

This will allow parentName to work for (perhaps silly?) nested subtest scenarios like this;

func (suite *SubTestSuite) TestSubSub() {
	for _, test := range []struct {
		testName string
	}{
		{"first"},
		{"second"},
	} {
		suite.Run(test.testName, func() {
			t := suite.T()
			assert.Contains(t, t.Name(), test.testName)
			suite.Run(test.testName+"sub", func() {
				tt := suite.T()
				assert.Contains(tt, tt.Name(), test.testName+"sub")
				suite.Run(test.testName+"subsub", func() {
					ttt := suite.T()
					assert.Contains(ttt, ttt.Name(), test.testName+"subsub")
				})
			})
		})
	}
}

func (suite *SubTestSuite) AfterSubTest(suiteName, testName, subtestName string) {
	fmt.Println("AFTER -> ", suiteName, testName, subtestName)
}

func (suite *SubTestSuite) BeforeSubTest(suiteName, testName, subtestName string) {
	fmt.Println("BEFORE -> ", suiteName, testName, subtestName)
}

which yields output like this;

=== RUN   Test_SubTest
=== RUN   Test_SubTest/TestSubSub
BEFORE ->  Test_SubTest TestSubSub first
=== RUN   Test_SubTest/TestSubSub/first
BEFORE ->  Test_SubTest TestSubSub/first firstsub
=== RUN   Test_SubTest/TestSubSub/first/firstsub
BEFORE ->  Test_SubTest TestSubSub/first/firstsub firstsubsub
=== RUN   Test_SubTest/TestSubSub/first/firstsub/firstsubsub
AFTER ->  Test_SubTest TestSubSub/first/firstsub firstsubsub
AFTER ->  Test_SubTest TestSubSub/first firstsub
AFTER ->  Test_SubTest TestSubSub first
BEFORE ->  Test_SubTest TestSubSub second
=== RUN   Test_SubTest/TestSubSub/second
BEFORE ->  Test_SubTest TestSubSub/second secondsub
=== RUN   Test_SubTest/TestSubSub/second/secondsub
BEFORE ->  Test_SubTest TestSubSub/second/secondsub secondsubsub
=== RUN   Test_SubTest/TestSubSub/second/secondsub/secondsubsub
AFTER ->  Test_SubTest TestSubSub/second/secondsub secondsubsub
AFTER ->  Test_SubTest TestSubSub/second secondsub
AFTER ->  Test_SubTest TestSubSub second
--- PASS: Test_SubTest (0.00s)
    --- PASS: Test_SubTest/TestSubSub (0.00s)
        --- PASS: Test_SubTest/TestSubSub/first (0.00s)
            --- PASS: Test_SubTest/TestSubSub/first/firstsub (0.00s)
                --- PASS: Test_SubTest/TestSubSub/first/firstsub/firstsubsub (0.00s)
        --- PASS: Test_SubTest/TestSubSub/second (0.00s)
            --- PASS: Test_SubTest/TestSubSub/second/secondsub (0.00s)
                --- PASS: Test_SubTest/TestSubSub/second/secondsub/secondsubsub (0.00s)
PASS

mach6 added a commit to mach6/testify that referenced this issue Mar 28, 2023
@dolmen dolmen added pkg-suite Change related to package testify/suite enhancement labels Jul 5, 2023
@dolmen dolmen changed the title Support for BeforeSubTest and AfterSubTest methods suite: Support for BeforeSubTest and AfterSubTest methods Jul 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement pkg-suite Change related to package testify/suite
Projects
None yet
Development

No branches or pull requests

3 participants