testify icon indicating copy to clipboard operation
testify copied to clipboard

Suite: Subtests should also trigger `SetupTest` and `TearDownTest`

Open odannyc opened this issue 4 years ago • 5 comments

I know this is probably a breaking change but I have some tests written using table driven design. I'd like for the tests ran with suite.Run(name string, func(){}) to also trigger SetupTest and TearDownTest for every instance of the subtest.

Is this currently possible?

If not then we can add a new func SetupSubtest and TearDownSubtest and run those for every subtest.

odannyc avatar Dec 14 '20 22:12 odannyc

I'm not sure that makes sense. Probably you have a specific case and think you need a common solution. Probably you need to implement your sub-tests as separate tests. Or need a helper method in your suite to call it to setup subtests (if you use a table-driven test it will be clear and simple). If you can provide more details (or peace of code) I can suggest to you more detailed.

I recommend investigating the flow of test execution. Look at this example — https://play.golang.org/p/ePSLrrfuV5m. SetupTest already executed before sub-test with other parent test code. So, proposed changes are the way to a sequence of SetupTest execution. I think you want to execute it once for every sub-test.

SetupSubtest sounds better, but it is not clear what to do with a sub-sub-test.

kulti avatar Dec 18 '20 09:12 kulti

I would also find SetupSubtest and TearDownSubTest very useful 😄 . I agree that is not clear what to do with a sub-sub-test though, don't know if there would be a way of limiting it to one level of depth only 🤔 I don't see why a deeper sub-test nesting would be useful anyway.

ghost avatar Oct 12 '21 17:10 ghost

Honestly I'm just shocked this still isn't a feature. It's pretty basic functionality considering they're clearly trying to imitate some of the concepts other test frameworks use (having hooks for pre- and post-tests)

azuk-bread avatar May 06 '22 16:05 azuk-bread

I needed a feature like BeforeSubtest to initialize the data in the database test. It's possible to split the test, but I wanted to use a subtest as the context.

func TestUserRepositoryTestSuite(t *testing.T) {
	suite.Run(t, new(UserRepositoryTestSuite))
}

func (s TestUserRepositoryTestSuite) BeforeTest(_ string, _ string) {
	testing_helper.CleanUpDB()
}

func NewUserRepositoryTestingContainer() *testing_helper.Container { # github.com/uber-go/dig.Container
	c := testing_helper.NewDatabaseTestingContainer()
	c.Provide(NewUserRepository)
	return c
}

func (s *UserRepositoryTestSuite) TestUserRepository_FindById() {
        id := 1
	c := NewUserRepositoryTestingContainer()
	c.RequireInvoke(func(repository repository.UserRepository) {
		s.Run("When user data exists", func() {
			testing_helper.CleanUpDB() # I want to call before each subtests.

                       testing_helper.DB.Create(&model.User{
                           ID: id,
                       })

			user, err := repository.FindById(id)
			s.NoError(err)
			s.Equal(user.ID, id)
		})
		s.Run("When user data not exists", func() {
			testing_helper.CleanUpDB()

			_, err := repository.FindById(id)
			s.ErrorIs(err, gorm.ErrRecordNotFound)
		})
	})
}

RSpec can be written as follows.

describe UserRepository do
  describe '#find_by_id' do
    before { DatabaseCleaner.clean } # Call before each it blocks.

    subject { UserRepository.find_by_id(id) }
    let(:id) { 1 }

    context 'When user data exists' do
      before { create(:user, id: id) }
      it { is_expected.not_to raise_error(ActiveRecord::RecordNotFound) }
      it { is_expected.to have_attriutes({id: id}) }
    end

    context 'When user data not exists' do
      it { is_expected.to raise_error(ActiveRecord::RecordNotFound) }
    end
  end
end

masato-hi avatar May 17 '22 19:05 masato-hi

I haven't tried this, but can't you just call suite.SetupTest() and suite.TearDownTest() yourself? Like so:

func (suite *MyTestSuite) TestSomeStuff() {
    ...
    for _, testCase := range testCases {
        suite.Run(testCase.name, func() {
            suite.SetupTest()
            ...
            suite.TearDownTest()
        })
    }
    ...
}

oscarjd74 avatar Jul 29 '22 12:07 oscarjd74