So I manage a bunch of services that are written in Go and they have to have a high level of test coverage.

The services have both unit tests and behaviour tests and recently I have been thinking about attempting to replace the behaviour tests and how best to do this.

The reason for this is that one or the other is always being forgotten about. And ideally I would just like less complexity and less things to maintain.

The behaviour tests are written in python using the Behave framework and our unit tests are of course written in Go.

The unit tests are behaviour tests are essentially testing the same thing just in slightly different ways and I want this blog post to provide the reason why I think this.

Lets explore the idea of writing unit tests but in a way so that they may feel like behaviour tests in terms of what they are testing.

Step one

Create a quick api route we can test

package mock_api

import "net/http"

func IndexRoute(w http.ResponseWriter, r *http.Request) {
	version := r.URL.Query().Get("v")

	w.Write([]byte(version))
}

Now we have setup a simple route that will return the version that it finds in the query string.

Step 2

Lets write a test which checks the http response body.

package mock_api_test

import (
	"bytes"
    "io"
    "net/http"
    "net/http/httptest"
    "testing"

    "git.sr.ht/~cubixle/mock_api"
)

func TestIndexRouteWithVersion(t *testing.T) {
    req := httptest.NewRequest(http.MethodGet, "http://localhost/?v=123", nil)
    recorder := httptest.NewRecorder()

    mock_api.IndexRoute(recorder, req)

    respBody, err := io.ReadAll(recorder.Result().Body)
    if err != nil {
            t.Fatal(err)
    }

    if !bytes.Equal(respBody, []byte("123")) {
            t.Fatalf("invalid response body (%s)", respBody)
    }
}

And there we have it. We have created a simple test that checks if the version we supplied in the query params is returned correctly in the http response.

I personally think that this "unit test" is very much like a behavior test. Why? Well because we are testing the behavior of this specific feature. We send a request with data and validate that the http response is what we expect. This is the same thing a behaviour test would check, althought that would be via a http server.

So the only thing we are not testing in this scenario is the http server itself.

I don't think this is necessary because we would usually let a third party package handle this functionality. Or it at least it would be an internal package to the company or project that has its own set of tests.

Of course this test doesn't come with a user story but should it? Adding a user story is adding complexity that just isn't needed for testing an API endpoint.

To prempt the point that this test isn't validating form data, thats fine that can also be done via building the http request.

Another point could be made about QA teams wanting to use behaviour tests for doing QA things. But shouldn't they have free reign of the technology they want to use? I guess if they wanted to run manual tests only, then they should be able to do that. Or if they were more comfortable using JS instead of Python they could do that. My point being a QA team should do QA things the way they want. They are the experts at it.

I guess (at this point) my conclusion is, I think behaviour testing should be left for either the QA team to decide. Or for testing user interfaces where validating button clicks or filling out input fields is required.