thelper detects golang test helpers without t.Helper()
call. Also, it checks the consistency of test helpers and has similar checks for benchmarks and TB interface. Read further to learn more.
With this call go test prints correct lines of code for failed tests. Otherwise, printed lines will be inside helpers functions.
Compare (https://goplay.space/#I_pAJ-vWcRq):
func TestBad(t *testing.T) {
testBad(t)
}
func testBad(t *testing.T) {
t.Fatal("unhelpful line") // <--- output point this line
}
func TestGood(t *testing.T) {
testGood(t) // <--- output point this line
}
func testGood(t *testing.T) {
t.Helper()
t.Fatal("clear output")
}
Why not? If you place it as the first call you unlikely add some assertion before.
It adds more consistency into your code. When common variables have the same name and placed into the same position it simpler to understand and read.
Note that it is not a strong restriction to be the first. It can be the second to be compatible with context.Context
param linting.
go get github.com/kulti/thelper/cmd/thelper
golangci-lint supports thelper, so you can enable this linter and use it.
Check everything:
thelper ./...
If you run via golangci-lint look at .golangci.example.yml for an example of the configuration.
Otherwise you can run thelper with --checks
command line argument. E.g. the following command checks that *testing.T
is the first param and *testing.B
has name b
:
thelper --checks=t_first,b_name ./...
- t_begin -
t.Helper()
should begin helper function. - t_name -
*testing.T
should have namet
. - t_first -
*testing.T
should be the first param of helper function.
The same for benchmarks and TB interface:
- b_begin -
b.Helper()
should begin helper function. - b_name -
*testing.B
should have nameb
. - b_first -
*testing.B
should be the first param of helper function. - tb_begin -
tb.Helper()
should begin helper function. - tb_name -
*testing.TB
should have nametb
. - tb_first -
*testing.TB
should be the first param of helper function.
- t_name allows using
_
name. - t_begin allows subtests not begin from
t.Helper()
. - t_first allows to be the second after
context.Context
param.
func TestSmth(t *testing.T) {
checkSmth(t)
}
// Bad
func checkSmth(t *testing.T) {
t.Fatal("check failed")
}
// Good
func checkSmth(t *testing.T) {
t.Helper()
t.Fatal("check failed")
}
// Bad
func checkSmth(tt *testing.T) {
// ...
}
// Good
func checkSmth(t *testing.T) {
// ...
}
// Bad
func checkSmth(doneCh <-chan struct{}, t *testing.T) {
// ...
}
// Good
func checkSmth(t *testing.T, doneCh <-chan struct{}) {
// ...
}