I want to use table-driven tests with DescribeTable, but some variables are created in a BeforeEach block. For example:
Describe("get user info", func() {
    type Form struct {
        Name  string
        Email string
    }
    var user *model.User
    BeforeEach(func() {
        user = db.CreateUser()
    })
    DescribeTable("pre validation",
        func(form Form, expectedErr error) {
            resp := APICall(form)
            Expect(resp.Err).Should(Equal(expectedErr))
        },
        Entry("name required", Form{Email: user.Email}, errors.New("name required")),
        Entry("email required", Form{Name: user.Name}, errors.New("email required")),
    )
})
The problem: BeforeEach runs only before each It, so user is nil when passed into Entry.
Am I approaching table-driven tests incorrectly?
What’s the recommended way to handle variables initialized in BeforeEach within DescribeTable?
             
            
              
              
              
            
           
          
            
            
              I ran into this exact issue when trying to use BeforeEach variables in DescribeTable.
The trick is that Entry is evaluated when the table is defined, not when the test runs, so any variables from BeforeEach aren’t available yet.
I solved it by wrapping the dynamic parts in functions or closures:
DescribeTable("pre validation",
    func(formFunc func() Form, expectedErr error) {
        form := formFunc()
        resp := APICall(form)
        Expect(resp.Err).Should(Equal(expectedErr))
    },
    Entry("name required", func() Form { return Form{Email: user.Email} }, errors.New("name required")),
    Entry("email required", func() Form { return Form{Name: user.Name} }, errors.New("email required")),
)
This way, the user variable is accessed after BeforeEach runs, and your tests get the correct data.
             
            
              
              
              
            
           
          
            
            
              From my experience, trying to use BeforeEach variables directly in Entry is a common pitfall.
Another approach is to keep the table static and generate the dynamic values inside the test function:
DescribeTable("pre validation",
    func(name string, email string, expectedErr error) {
        form := Form{Name: name, Email: email}
        resp := APICall(form)
        Expect(resp.Err).Should(Equal(expectedErr))
    },
    Entry("name required", "", "user@example.com", errors.New("name required")),
    Entry("email required", "Test User", "", errors.New("email required")),
)
Here, you use placeholders in the table and then use BeforeEach to populate shared resources like user.Email if needed, or override them in the function body.
             
            
              
              
              
            
           
          
            
            
              I also experimented with helper functions that capture BeforeEach variables.
Essentially, you define a function that returns the table entries after the BeforeEach has run:
var tableEntries func() []TableEntry
BeforeEach(func() {
    user = db.CreateUser()
    tableEntries = func() []TableEntry {
        return []TableEntry{
            Entry("name required", Form{Email: user.Email}, errors.New("name required")),
            Entry("email required", Form{Name: user.Name}, errors.New("email required")),
        }
    }
})
DescribeTable("pre validation",
    func(form Form, expectedErr error) {
        resp := APICall(form)
        Expect(resp.Err).Should(Equal(expectedErr))
    },
    tableEntries()..., // spread the entries after BeforeEach
)
This ensures the entries are only created after the BeforeEach variables are ready, preserving the table-driven pattern.