You have no excuses now, use this free credit to launch your projects now on Digital Ocean, you're free to spend it whenever you want within the following 60 days.
Table of contents
Go: basic testing and coverage
Go: basic testing and coverage
Go already has a testing module in its standard library that is ready for our use, we just need to import it and use it.
Testing preparation in go
For the tests to be carried out we need:
A file ending in _test.go * A file ending in _test.go * Run the command go test.
- Run the go test command
├── go.mod
├── main.go
└── testing
├── main.go
└── main_test.go
1 directory, 5 files
Consider that, if you are going to assign a name to your package , you should never name it testing. Why? If you do, go will confuse its testing package with yours, returning those incorrect results.
To create the tests, inside the testing/main_test.go file, we need a function that receives as argument our testing package with the destructuring character.
We will compare the result using an if, or whatever we want and, if the test fails, we will call the Errorf method of the testing module.
package main
import "testing"
func TestDivision(t *testing.T) {
total := Division(10, 2)
if total != 5 {
t.Errorf("División incorrecta, obtuvimos %d pero se esperaba %d", total, 5)
}
}
It is not necessary that the functions to be tested are inside the testing file, in this case I placed them inside testing/main.go.
package main
func Division(a int, b int) int {
return a / b
}
Execute tests
To run the tests we need to find ourselves inside the directory where our files ending in _test.go are located and run the go test command. If the test passes we will get the PASS message.
cd testing/
go test
PASS
ok main/testing 0.001s
On the other hand, if the tests fail, the word FAIL will be printed on the screen:
--- FAIL: TestDivision (0.00s)
main_test.go:14: División incorrecta, obtuvimos 12 pero se esperaba 5
FAIL
exit status 1
FAIL main/testing 0.001s
Case management with tables
In the above example we used one function to test one case, however, if we needed to test multiple cases, we would need a function for each test, quite tedious, right?
To avoid filling up with functions, developers use an array composed of structs, where each struct represents a case to be tested. You can think of the array of structs as a table, where each row is a case and each column is a data type to be tested.
In this case, each struct in our array consists of three integers; the first two represent the arguments, while the last one is the result.
tables := []struct {
x int
y int
r int
}{
{100, 10, 10}, // 100 / 10 = 10
{200, 20, 10}, // 200 / 20 = 10
{300, 30, 10},
{1000, 100, 10},
}
I’m sure you’ve noticed that we’re not covering division by zero, but leave it at that for now.
Now that we have our array of structs, we will iterate over each of its elements using go’s range function . This way we will cover each case.
for _, table := range tables {
total := Division(table.x, table.y)
if total != table.r {
t.Errorf("División de %d entre %d incorrecta, obtuvimos: %d, pero el resultado es: %d.", table.x, table.y, total, table.r)
}
}
If everything went well, we will pass all the tests.
Coverage
Coverage is already part of the code in go, so we do not need external libraries. If you don’t know what Coverage is, think of it as the percentage of your code that is tested. If all your code goes through the tests you will have a coverage of 100%, if only half of it goes through the tests the coverage will be 50%. Previously I talked about coverage in my entry unittest in Python
To calculate the coverage, simply add the -cover flag to the go test command.
go test -cover
PASS
coverage: 100.0% of statements
ok _/home/eduardo/Programacion/goTesting/testing 0.002s
As our function is tiny, we obtain a result of 100%, without breaking down, from coverage
Export coverage results
We can send all the raw data from our coverage test to an external file with the -coverprofile flag.
go test -coverprofile=coverage.out
mode: set
/home/eduardo/Programacion/goTesting/testing/main.go:3.33,5.2 1 1
This file, named coverage.out, which was generated, is a file containing raw data and will be needed to visualize the results in a more detailed way.
Viewing results with go tool
To summarize in a more readable way the information of the file containing our coverage test, we will use the tool command, accompanied by the -func flag, followed by the file name. This will return a broken down coverage result.
go tool cover -func=coverage.out
/home/eduardo/Programacion/goTesting/testing/main.go:3: Division 100.0%
total: (statements) 100.0%
Go also allows us to visualize the coverage in HTML format, with colors, directly in our browser. For this we use the -html option, followed by the file with the coverage data.
When the command is executed, a browser tab will open and show the tested results in green and the untested results in red.
go tool cover -html=coverage.out
Full html coverage in go
If we decide to modify our function to handle the division by zero cases, and run the coverage tests again, we will get a different scheme than before. Now a section of code not covered by the tests appears in red and our coverage dropped to 50%.
Incomplete html coverage in go
This is the end of this super short entry about go testing. For the next entry I will talk a little bit about profiling and I will finish the basic go entries to write again about Python.