# Improving Go Unit Tests: t.Run Over Table Tests
Table-driven tests in Go are a widespread way to structure unit tests, making it easier to spot missing cases and (somewhat) easier to maintain over time.
However, they have a significant downside: when a test fails, identifying the exact failing case requires looking for the test name in the `go test` output, and searching for it in the test file.
Take this example from [undent_test.go](https://github.com/maelvls/tppctl/blob/main/undent/undent_test.go):
```go
func Test_Undent(t *testing.T) {
tests := []struct {
name string
given string
expected string
}{
{
name: "empty string",
given: ``,
expected: ``,
},
{
name: "if last line has the same indent as other lines and, it is ignored",
given: `
foo
bar
`,
expected: "foo\nbar\n",
},
{
name: "you can un-indent the last line to make the Go code more readable",
given: `
foo
bar
`,
expected: "foo\nbar\n",
},
{
name: "last line may not be an empty line",
given: `foo\nbar`,
expected: "foo\nbar",
},
{
name: "1 empty line is preserved",
given: "\t\tfoo\n\t\t\n\t\tbar\n",
expected: "foo\n\nbar\n",
},
{
name: "2 empty lines are preserved",
given: "\t\tfoo\n\t\t\n\t\t\n\t\tbar\n",
expected: "foo\n\n\nbar\n",
},
{
name: "you can also omit the tabs or spaces for empty lines",
given: `
foo
bar
`,
expected: "foo\n\nbar\n",
},
{
name: "bug fix: last char is not omitted",
given: "\t\t{\n\t\t \"kind\": \"Secret\"\n\t\t}",
expected: "{\n \"kind\": \"Secret\"\n}",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Undent(tt.given)
assert.Equal(t, tt.expected, got)
})
}
}
```
The issue I find with table tests based on a slice of some struct is that it won't show you which test case is failing. You have to search for the name of the test that just failed...
A better way I found is to use `t.Run` instead:
```go
func Test_Undent(t *testing.T) {
t.Run("empty string", runTest_Undent(``, ``))
t.Run("if last line has the same indent as other lines and, it is ignored", runTest_Undent(`
foo
bar
`, "foo\nbar\n"))
t.Run("you can un-indent the last line to make the Go code more readable", runTest_Undent(`
foo
bar
`, "foo\nbar\n"))
t.Run("last line may not be an empty line", runTest_Undent(`
foo
bar`, "foo\nbar"))
t.Run("1 empty line is preserved", runTest_Undent("\t\tfoo\n\t\t\n\t\tbar\n", "foo\n\nbar\n"))
t.Run("2 empty lines are preserved", runTest_Undent("\t\tfoo\n\t\t\n\t\t\n\t\tbar\n", "foo\n\n\nbar\n"))
t.Run("you can also omit the tabs or spaces for empty lines", runTest_Undent(`
foo
bar
`, "foo\n\nbaar\n"))
t.Run("bug fix: last char is not omitted", runTest_Undent("\t\t{\n\t\t \"kind\": \"Secret\"\n\t\t}", "{\n \"kind\": \"Secret\"\n}"))
}
func runTest_Undent(given, expected string) func(t *testing.T) {
return func(t *testing.T) {
t.Helper() // Important, see below.
got := "Undent(given)"
assert.Equal(t, expected, got)
}
}
```
This way, the error points directly to the test case failing, and you no longer have to search.
Are you can see, the line count is similar.
Another benefit is that VSCode lets you click the "Test" button on a `t.Run` subtest when you are writing tests this way:

**About `t.Helper()`:** if your line number is off (shows the line of your `t.Error`
instead of the location of the test case's `t.Run`), remember to use
`t.Helper()`.