Go Cover: A Neat Tool to Achieve 100% Coverage

Sep 29, 2020

2 mins read

When writing software for production, inevitably you will have to write some unit tests to ensure the functionalities are working just fine in certain scenarios.

Though it is hard to test every potential cases in practice, there are some practical measures you can rely on to inspect what percentage your code is tested, the coverage.

Built-in coverage tool

Usually you will use go test . to run test files, and in addition, go test . -v to inspect some log if necessary.

If you want to know the coverage of the test, you can run:

➜  go test . -cover
ok      some_pkg      0.466s  coverage: 91.6% of statements

Here you can see that there are 91.6% of codes tested.

Note that even 100% does not guarantee all the scenario has been tested, just means that the code has been tested in limited ways.

Visualize

But how do I know which line of code has not been tested? We can definitely do better. By -coverprofile:

➜  go test . -coverprofile cover.out
ok      some_pkg      0.466s  coverage: 91.6% of statements

The -coverprofile tells go test to generate a profile of coverage. You will find out it is hard to read. That’s because it should be read by:

➜  go tool cover -html=cover.out 

It will open a browser and display the profile with a basic UI.

But it contains meaningful information! You can inspect that the line painted in red is actually some code that has not been tested, figure a way to test it :)

Coverall and Goverall

After knowing how to inspect the percentage of testing, you can try to do it automatically. That is where Coveralls and Goveralls come into play.

  • Coveralls is a service that can link to your github repo and trigger when you push to the origin, you will have to sign in with Github (or other repository host).

  • Goveralls is a wrapper that consume your coverage output and send it to Coveralls

With them, all you have to do is set up your CI workflow (use Github Action for example) as below:

name: CI
on: [push, pull_request]
jobs:
  test:
    name: Test with Coverage
    runs-on: ubuntu-latest
    steps:
    - name: Set up Go
      uses: actions/setup-go@v1
      with:
        go-version: '1.13'
    - name: Check out code
      uses: actions/checkout@v2
    - name: Install dependencies
      run: |
        go mod download
    - name: Run Unit tests
      run: |
        go test -race -covermode atomic -coverprofile=covprofile ./...
    - name: Send coverage
      env:
        COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        go get github.com/mattn/goveralls
        /home/runner/go/bin/goveralls -coverprofile=covprofile -service=github

Finally, you can inspect the coverage report once you have changes in your repo :)

Sharing is caring!