Go > Testing and Benchmarking > Unit Testing > Test coverage

Calculating and Displaying Test Coverage in Go

This example demonstrates how to write unit tests in Go and calculate the test coverage using the `go test` command with the `-cover` flag. We'll create a simple function, write a test for it, and then generate a coverage report to see how much of our code is being tested. Understanding test coverage helps ensure the reliability and robustness of your Go applications.

Function to be Tested

This is a simple `Add` function that takes two integers as input and returns their sum. We will write a unit test to verify that this function works correctly.

package main

// Add adds two integers and returns the result.
func Add(a, b int) int {
	return a + b
}

Unit Test for the Add Function

This is the unit test for the `Add` function. It uses a table-driven test approach, where we define a slice of test cases, each with a name, input values (a and b), and the expected output. The `t.Run` function allows us to run each test case individually. Inside each test case, we call the `Add` function with the input values and compare the actual result with the expected result. If they don't match, we use `t.Errorf` to report an error.

package main

import "testing"

func TestAdd(t *testing.T) {
	table := []struct {
		name     string
		a, b     int
		expected int
	}{
		{"Positive numbers", 2, 3, 5},
		{"Negative numbers", -1, -2, -3},
		{"Zero and positive", 0, 5, 5},
		{"Zero and negative", 0, -3, -3},
	}

	for _, tt := range table {
		t.Run(tt.name, func(t *testing.T) {
			actual := Add(tt.a, tt.b)
			if actual != tt.expected {
				t.Errorf("Add(%d, %d): expected %d, actual %d", tt.a, tt.b, tt.expected, actual)
			}
		})
	}
}

Running Tests and Generating Coverage Report

To run the tests and generate a coverage report, use the `go test -cover` command. This will run all the tests in the current directory and print the coverage percentage. To generate a more detailed HTML coverage report, you can use the following commands: 1. `go test -coverprofile=coverage.out`: This command runs the tests and writes the coverage data to a file named `coverage.out`. 2. `go tool cover -html=coverage.out`: This command uses the `go tool cover` to generate an HTML report from the `coverage.out` file. The HTML report will show you which lines of code were executed during the tests and which lines were not.

// To run the tests and generate a coverage report, use the following command:
// go test -cover

// To generate an HTML coverage report, use the following commands:
// go test -coverprofile=coverage.out
// go tool cover -html=coverage.out

Understanding Test Coverage

Test coverage is a metric that indicates the percentage of your code that is executed by your tests. A higher coverage percentage generally means that your code is more thoroughly tested, and therefore more likely to be reliable. However, it's important to note that high test coverage doesn't guarantee that your code is bug-free. It only means that more of your code has been executed by tests. The quality of the tests is just as important as the quantity.

Real-Life Use Case

In a real-world application, you would use test coverage to identify areas of your code that are not being adequately tested. For example, if you have a complex function with multiple branches, you might find that your tests only cover one or two of those branches. By looking at the coverage report, you can identify the missing tests and write additional tests to cover those branches. This will help you to ensure that your function is working correctly in all possible scenarios.

Best Practices

  • Aim for High Coverage: While 100% coverage isn't always necessary or feasible, strive for a high percentage (e.g., 80% or higher) to ensure that most of your code is being tested.
  • Write Meaningful Tests: Focus on writing tests that cover the important aspects of your code and exercise different scenarios.
  • Use Table-Driven Tests: Table-driven tests are a great way to organize your tests and make them more readable and maintainable.
  • Regularly Check Coverage: Make it a habit to run coverage reports regularly, especially after making changes to your code.

Interview Tip

Be prepared to discuss the importance of test coverage, how to calculate it in Go, and how to use it to improve the quality of your code. Also, be ready to explain the difference between statement coverage, branch coverage, and path coverage.

When to use them

Use test coverage during development, continuous integration, and code review. It's a valuable tool for monitoring the quality of your codebase.

Alternatives

Mutation testing is an alternative approach that introduces small changes (mutations) into your code and checks if your tests can detect these changes. It can be a more comprehensive way to evaluate the effectiveness of your tests than simple coverage analysis.

pros

  • Identifies untested code.
  • Encourages writing more tests.
  • Provides a metric for code quality.

cons

  • High coverage doesn't guarantee bug-free code.
  • Can be time-consuming to achieve high coverage.
  • Can lead to writing trivial tests just to increase coverage.

FAQ

  • What does `go test -cover` do?

    The `go test -cover` command runs the tests in your package and calculates the test coverage. It prints the coverage percentage to the console.
  • How can I generate an HTML coverage report?

    Use the following commands: `go test -coverprofile=coverage.out` and then `go tool cover -html=coverage.out`. This will generate an HTML report that you can view in your browser.
  • Is 100% test coverage always necessary?

    No, 100% test coverage is not always necessary or feasible. It's more important to focus on writing meaningful tests that cover the important aspects of your code. Sometimes, achieving 100% coverage can lead to writing trivial tests that don't add much value.