As your services become more intricate and complex, so too does your test setup and teardown. Thankfully, this is where the TestMain
function can help save the day.
If you need a particular bit of code to execute once within a given test package then you can utilize the TestMain
function to handle this execution.
A Simple Implementation
Let’s start off with a simple implementation that will highlight how this works, then when we have the basics down we can build on top of this a little and get a better indication as to how we can use this within our own testing strategies.
ackage yamltohtml_test
import (
"fmt"
"os"
"testing"
"github.com/TutorialEdge/go-testing-bible/yamltohtml"
)
type TestCase struct {
desc string
path string
expected string
}
func TestMain(m *testing.M) {
fmt.Println("Hello World")
ret := m.Run()
fmt.Println("Tests have executed")
os.Exit(ret)
}
...
Let’s try run this now in the terminal:
$ go test yamltohtml/yamltohtml_test.go -v
Hello World
=== RUN TestYamlToHTML
=== RUN TestYamlToHTML/Test_Case_1
TestYamlToHTML/Test_Case_1: yamltohtml_test.go:45: <html><head><title>My Awesome Page</title></head><body>This is my awesome content</body></html>
=== RUN TestYamlToHTML/Test_Case_2
TestYamlToHTML/Test_Case_2: yamltohtml_test.go:45: <html><head><title>My Second Page</title></head><body>This is my awesome content</body></html>
--- PASS: TestYamlToHTML (0.00s)
--- PASS: TestYamlToHTML/Test_Case_1 (0.00s)
--- PASS: TestYamlToHTML/Test_Case_2 (0.00s)
PASS
Tests have executed
ok command-line-arguments 3.103s
You
An Alternative Approach Using Subtests
Now, there is an alternative approach you could consider which is defaulting to using subtests wrapped in Test functions and handling initialization at the parent test level.
Let’s look at an example:
package _test
func TestCalculate(t *testing.T) {
client := Client{
DB: "localhost"
}
fmt.Println("Parent Test Level")
t.Run("My Test 1", func(t *testing.T) {
// does something with client
fmt.Println("Test Case 1")
})
t.Run("My Test 2", func(t *testing.T) {
// does something with client
fmt.Println("Test Case 2")
})
}
What happens when we execute this?
$ go test ./... -v
This approach does work when you need your initialization code to be ever so slightly different, however if you need the initialization code to only run once then the better candidate is definitely delegating this logic to your TestMain
function.
Conclusion
In this tutorial, we looked at how you can simplify your lives by using TestMain
to handle all of the setup for your test suites. In the next tutorial in this course, we’ll be looking at the best practices around object comparisons in Go and how you can check for equality using the reflect
package.