In Go, you can easily write unit tests using the various features (e.g. assertion, mocking, suite) provided by the testify library. There are cases where you need to skip the entire test depending on a particular config setting. In such cases, you can easily handle that scenario using a Test Suite.
- e.g. cluster_test.go - run only when in redis cluster mode
When you run the suite.Run() method, the methods defined in the Suite run in order, so if you put a condition before that and call the t.Skip() method when it's true, the entire test is skipped.
func TestExampleTestSuite(t *testing.T) {
//under a specific condition, you can choose not to run the entire test
if isSkip() {
t.Skip("skipping")
}
suite.Run(t, new(ExampleTestSuite))
}
func isSkip() bool {
return false
}
The Suite package provides several interfaces before and after test execution, allowing various processing before and after tests. Let's look at the various life cycle methods. By examining the execution logic of suite.Run(), you can see at which point in the test execution life cycle the suite interface methods run.
func Run(t *testing.T, suite TestingSuite) {
...omitted...
if afterTestSuite, ok := suite.(AfterTest); ok {
afterTestSuite.AfterTest(suiteName, method.Name)
}
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
tearDownTestSuite.TearDownTest()
}
...omitted...
}
º
- Setup
SetupSuite- runs only once before all tests in the suiteSetupTest- runs before each test in the suiteBeforeTest- a function that runs before a test, takingsuiteName, testNamearguments
- Teardown
AfterTest- a function that runs after a test, taking suiteName testName argumentsTearDownTest- runs after each test in the suiteTestDownSuite- runs after all tests in the suite have run
To write tests with a Test Suite, create a struct that embeds the suite.Suite struct and define suite methods on that struct.
type ExampleTestSuite struct {
suite.Suite
}
func (ets *ExampleTestSuite) SetupSuite() {}
...omitted...
func (ets *ExampleTestSuite) TestExample1() {}
Here is the full test code that was written.
type ExampleTestSuite struct {
suite.Suite
TestValue int
}
//runs only once before all tests in the suite
func (ets *ExampleTestSuite) SetupSuite() {
fmt.Println("SetupSuite :: run once")
}
//runs before each test in the suite
func (ets *ExampleTestSuite) SetupTest() {
fmt.Println("SetupTest :: run setup test")
ets.TestValue = 5
}
//a function that runs before a test, taking suiteName testName arguments
func (ets *ExampleTestSuite) BeforeTest(suiteName, testName string) {
fmt.Printf("BeforeTest :: run before test - suiteName:%s testName: %s\n", suiteName, testName)
}
//TEST ----------------------------------------
func (ets *ExampleTestSuite) TestExample1() {
fmt.Println("TestExample1")
assert.Equal(ets.T(), ets.TestValue, 5) //you can check assertions this way, but
ets.Equal(ets.TestValue, 5) //to check assertions you can use it like this.
}
func (ets *ExampleTestSuite) TestExample2() {
fmt.Println("TestExample2")
}
//TEST ----------------------------------------
//a function that runs after a test, taking suiteName testName arguments
func (ets *ExampleTestSuite) AfterTest(suiteName, testName string) {
fmt.Printf("AfterTest :: suiteName:%s testName: %s\n", suiteName, testName)
}
//runs after each test in the suite
func (ets *ExampleTestSuite) TearDownTest() {
fmt.Println("TearDownTest :: run before after test")
}
//runs once after all tests in the suite have run
func (ets *ExampleTestSuite) TearDownSuite() {
fmt.Println("TearDownSuite :: run once")
}
func TestExampleTestSuite(t *testing.T) {
//under a specific condition, you can choose not to run the entire test
if isSkip() {
t.Skip("skipping")
}
suite.Run(t, new(ExampleTestSuite))
}
func isSkip() bool {
return false
}
Shall we run the test and check the life cycle?
=== RUN TestExampleTestSuite
SetupSuite :: run once
--- PASS: TestExampleTestSuite (0.00s)
=== RUN TestExampleTestSuite/TestExample1
SetupTest :: run setup test
BeforeTest :: run before test - suiteName:ExampleTestSuite testName: TestExample1
TestExample1
AfterTest :: suiteName:ExampleTestSuite testName: TestExample1
TearDownTest :: run before after test
--- PASS: TestExampleTestSuite/TestExample1 (0.00s)
=== RUN TestExampleTestSuite/TestExample2
SetupTest :: run setup test
BeforeTest :: run before test - suiteName:ExampleTestSuite testName: TestExample2
TestExample2
AfterTest :: suiteName:ExampleTestSuite testName: TestExample2
TearDownTest :: run before after test
TearDownSuite :: run once
--- PASS: TestExampleTestSuite/TestExample2 (0.00s)
PASS