A logo showing the text blog.marcnuri.com
Español
Home»Go»How to set up and tear down unit tests in Go

Recent Posts

  • MCP Tool Annotations: Adding Metadata and Context to Your AI Tools
  • Fabric8 Kubernetes Client 7.2 is now available!
  • Connecting to an MCP Server from JavaScript using AI SDK
  • Connecting to an MCP Server from JavaScript using LangChain.js
  • The Future of Developer Tools: Adapting to Machine-Based Developers

Categories

  • Artificial Intelligence
  • Front-end
  • Go
  • Industry and business
  • Java
  • JavaScript
  • Legacy
  • Operations
  • Personal
  • Pet projects
  • Tools

Archives

  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • August 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • February 2020
  • January 2020
  • December 2019
  • October 2019
  • September 2019
  • July 2019
  • March 2019
  • November 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • December 2017
  • July 2017
  • January 2017
  • December 2015
  • November 2015
  • December 2014
  • March 2014
  • February 2011
  • November 2008
  • June 2008
  • May 2008
  • April 2008
  • January 2008
  • November 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007

How to set up and tear down unit tests in Go

2023-10-12 in Go tagged Go / Testing / Test-Driven Development (TDD) by Marc Nuri | Last updated: 2025-02-11
Versión en Español

Introduction

When writing unit tests in Go, it's sometimes useful to perform common actions that need to be executed before and after a test. These setup and tear-down tasks might be needed in different scopes:

  • Before and after the full test suite is executed.
  • Before and after each test is executed.
  • Or even before and after a group of tests is executed.

Coming from a Java background, this is a common practice. Testing frameworks such as JUnit have built-in annotations that provide this functionality in an aspect-oriented way. However, achieving the same in Go with the standard testing library has been a bit elusive. In this article, I'll show you how to accomplish these tasks in Go.

Running code before and after the full test suite

Starting with Go 1.4, the standard library provides a way to run code before and after the full test suite is executed. If a test file in a package contains a function with the signature:

func TestMain(m *testing.M)

Go will execute that function instead of running the tests directly. You can learn more about this function in the Go standard library documentation.

A typical implementation of this function would be:

func TestMain(m *testing.M) {
  // Setup code goes here
  code := m.Run()
  // Teardown code goes here
  os.Exit(code)
}

This function allows us to run code before and after the full test suite is executed. To execute the tests, we need to call m.Run().

Note

Note how we store the result of m.Run() in a variable and then call os.Exit(code) to exit the program with the proper exit code.

Things to consider:

  • You can define this function in any of your package test files.
  • Function names are unique in a given package, you can only define only one TestMain function per package.
  • If your package contains multiple test files, place the TestMain function wherever it makes the most sense.
  • If you don't call os.Exit with the m.Run() return code, your test command will always return 0 (even if it fails).

Let's now learn how to run code before and after a group of tests.

Running code before and after a group of tests

Another common scenario is to run code or prepare the testing environment before a group of tests is executed. Go subtests are very useful in this case.

Subtests leverage the t.Run(name string, f func(t *T)) function to run the provided f function as a subtest of t.

Let's see an example:

func TestSomethingWhenGivenCondition(t *testing.T) {
  // Setup code for given condition goes here
  t.Run("Something has property one", func(t *testing.T) {
    // Subtest 1 code goes here
  })
  t.Run("Something has property two", func(t *testing.T) {
    // Subtest 2 code goes here
  })
  // Teardown code for given condition goes here
}

Suppose we want to test the behavior of our application given an environment with specific conditions. Subtests allow us to group these tests under a function, in this case, TestSomethingWhenGivenCondition.

This function allows us to set up and tear down the environment by running code before and after the subtest invocations. We can then run a subtest using the t.Run function for each property or behavior of the application we want to test.

You can find a complete example at this link. Let us now see how to run code before and after each individual test.

Running code before and after each test

The Go standard testing library doesn't provide a built-in way to run code before and after each test. For this purpose, we need to provide a workaround implementation. This is what I usually do.

Create a struct to hold the test context that will be initialized and torn down before and after each test.

type testContext struct {
  some    string
  test    *pkg.Var
  context int64
}

func (c *testContext) beforeEach() {
  // Setup code for context goes here
}

func (c *testContext) afterEach() {
  // Teardown code for context goes here
}

Next, define a function that's used to encapsulate each test:

func testCase(test func(t *testing.T, c *testContext)) func(*testing.T) {
  return func(t *testing.T) {
    context := &testContext{}
    context.beforeEach()
    defer context.afterEach()
    test(t, context)
  }
}

Finally, use this function in a subtest:

func TestSomething(t *testing.T) {
  t.Run("Some test case", testCase(func(t *testing.T, c *testContext) {
    // Test code goes here which can leverage the context
  }))
}

For each test invocation, a new testContext is created and the beforeEach and afterEach functions are called before and after the test is executed.

You can find a complete example at this link.

Conclusion

In this article, we've seen how to properly set up and tear down a Go unit test using Go's standard library for unit testing. We've seen how to run code before and after the full test suite, before and after a group of tests, and before and after each test. These techniques will help you write robust and well-organized tests in your Go projects.

Happy testing!

You might also like

  • How to initialize a new Go project with modules
  • Testing Go Gin Web Framework REST APIs with httptest
  • Getting started with Testcontainers for Go
Twitter iconFacebook iconLinkedIn iconPinterest iconEmail icon

Post navigation
Testing Go Gin Web Framework REST APIs with httptestFabric8 Kubernetes Client 6.9 is now available!
© 2007 - 2025 Marc Nuri