how to use build tags to control GO testing with a GitLab CI use case

abstract

The importance of testing code in programming is undoubtedly a fact. There cannot be good quality development without proper testing coverage. Sometimes, however, it is necessary to distinguish the tests or even launch them grouped …


This content originally appeared on DEV Community and was authored by enbis

abstract

The importance of testing code in programming is undoubtedly a fact. There cannot be good quality development without proper testing coverage. Sometimes, however, it is necessary to distinguish the tests or even launch them grouped together rather than all at once. This is the purpose of these few lines: present a valid solution for GO developers who wants to run their tests separately.

The use case I prepared involves a dummy GO project with test files. It has been pushed on a GitLab repository to run the Continuous Integration, while diversifying tests. This is the link to inspect the solution directly on GitLab.

prerequisites

  • basic knowledge of GO programming and testing
  • basic knowledge of the GitLab-CI

the GO project

Let's start our tour presenting the pilot GO project used to evaluate the usefulness of build tags. It is a simple Web Server with the sole purpose of handling http requests based on this URL query string /?value=10. Assuming the value is numeric, the web server returns a JSON payload with a success status and the value increased by one unit.

{"status":"success","result":"11"}

In case of invalid request it returns JSON payload with a fail status and the error.

{"status":"fail","error":"strconv.Atoi: parsing \"10a\": invalid syntax"}

the project layout

In this scenario, the GO project has two packages besides the main: handler and helper.

  • handler: decodes the http request and returns the answer after processing the data received
  • helper: exposes the functions to manipulate the data

the test files

The layout presented allows me to separate the context for the testing stage.
The handler can be tested using the net/http/httptest GO std library package. The handler_internal_test contains the httptest functions NewRequest and NewRecorder to prepare the http.Request and evaluate the http.Response. This could be identified as a sort of integration test.

func TestHandler(t *testing.T) {
    var response Response

    req := httptest.NewRequest("GET", "/?value=10", nil)
    w := httptest.NewRecorder()
    Handler(w, req)

    res := w.Result()
    defer res.Body.Close()

    assert.Equal(t, http.StatusOK, res.StatusCode)

    data, err := ioutil.ReadAll(res.Body)
    assert.NoError(t, err)

    err = json.Unmarshal(data, &response)
    assert.NoError(t, err)

    assert.Equal(t, "11", response.Result)
}

The helper package contains the functions used to process the data. Those functions can be tested as a pure unit tests. This is the helper_internal_test created.

func TestConvert(t *testing.T) {
    tables := []struct {
        in  string
        out int
    }{
        {"1", 1},
        {"100", 100},
    }

    for _, table := range tables {
        converted, err := Convert(table.in)
        assert.NoError(t, err)
        assert.Equal(t, table.out, converted)
    }
}

func TestIncrement(t *testing.T) {
    tables := []struct {
        in  int
        out int
    }{
        {1, 2},
        {100, 101},
    }

    for _, table := range tables {
        converted := Increment(table.in)
        assert.Equal(t, table.out, converted)
    }
}

func TestToString(t *testing.T) {
    tables := []struct {
        in  int
        out string
    }{
        {1, "1"},
        {100, "100"},
    }

    for _, table := range tables {
        str := ToString(table.in)
        assert.Equal(t, table.out, str)
    }
}

the build tags ( or build constraints )

What we produced so far is the Web Server and its test files. As a GO developer I just have to run the command go test ./... and my whole list of tests is executed.
The point is that I cannot distinguish between integration test and unit test or even have a separate report in a GitLab pipeline.
Here is where the build tags become useful. On top of that, they are easy to integrate into the code.
The syntax is a comment on top of the test file, with the special word +build followed by the keyword that identifies the tag. The constrains are injected into GO using -tags flag in the test command.
Let's see what happens in practical terms:

  • integration test: the chosen keyword is integration, so I need to add the comment // +build integration on top of the handler_internal_test file and run the command go test ./... -tags=integration to execute it.
// +build integration

package handler

import (
    "encoding/json"
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestHandler(t *testing.T) {
....
....
  • unit test: the keyword in this case is unit, I need to add the comment // +build unit on top of the helper_internal_test file and run the command go test ./... -tags=unit
// +build unit

package helper

import (
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestConvert(t *testing.T) {
  • unit and integration test: tags syntax allows to use AND and OR, as well as negative expressions. To run both at the same time, the command to use is go test ./... -tags=integration,unit

the GitLab CI pipeline

Last but not least, the integration of the build tags into the GitLab CI pipeline. In this case the purpose could be to see the result of the tests grouped by tags. The case presented here contains only two tags: integration and unit. The gitlab-ci.yml file will have two stages, each with the proper script.

stages:
  - unit_test
  - integration_test

unit:
  stage: unit_test
  script:
    - go test -v ./... -tags=unit

integration:
  stage: integration_test
  script:
    - go test -v ./... -tags=integration

Which brings this result:

Alt Text

Thanks to the build tags in the GitLab pipeline presented above I'm able to distinguish tests by context, run them separately and inspect the result individually.


This content originally appeared on DEV Community and was authored by enbis


Print Share Comment Cite Upload Translate Updates
APA

enbis | Sciencx (2021-10-03T20:09:39+00:00) how to use build tags to control GO testing with a GitLab CI use case. Retrieved from https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/

MLA
" » how to use build tags to control GO testing with a GitLab CI use case." enbis | Sciencx - Sunday October 3, 2021, https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/
HARVARD
enbis | Sciencx Sunday October 3, 2021 » how to use build tags to control GO testing with a GitLab CI use case., viewed ,<https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/>
VANCOUVER
enbis | Sciencx - » how to use build tags to control GO testing with a GitLab CI use case. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/
CHICAGO
" » how to use build tags to control GO testing with a GitLab CI use case." enbis | Sciencx - Accessed . https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/
IEEE
" » how to use build tags to control GO testing with a GitLab CI use case." enbis | Sciencx [Online]. Available: https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/. [Accessed: ]
rf:citation
» how to use build tags to control GO testing with a GitLab CI use case | enbis | Sciencx | https://www.scien.cx/2021/10/03/how-to-use-build-tags-to-control-go-testing-with-a-gitlab-ci-use-case/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.