External behavior and integration testing

As seen, the creation of unit tests and benchmark tests within Go is very simple and intuitive. The built in go test command allows various coverage capabilities. A little known capability of the go test tool is the ability to specify which packages you wish to generate coverage information about with the -coverpkg flag. Armed with this information, we can formulate a go test command that will be able to run against the main package in our program but collect coverage information about our handlers package:

go test -coverprofile=cov.txt -coverpkg ./handlers -run TestRunMain ./cmd/service/

The preceding command is saying run tests against the main package but collect the coverage information from handlers that in turn will use the cover tool to instrument the handlers code to keep track of coverage numbers in the handlers package. If we take this concept to the next logical step, what happens if we have one test in cmd/service/main_test.go that merely runs the main entry point of our web application? For our thought experiment, here are the contents of cmd/service/main_test.go followed by the modifications to $GOPATH/src/github.com/PacktPublishing/Echo-Essentials/chapter7/cmd/service/main_test.go:

package main

import (
        "testing"
)

func TestRunMain(t *testing.T) {
        TestRun = true
        go main()
        <-StopTestServer
        TestRun = false
}

Next, you will see how we alter main.go to include the TestRun variable and the StopTestServer channel which are used to tell main that this is a test version of the server, and when to stop processing:

var (
        StopTestServer = make(chan bool)
        TestRun        = false
)

func main() {
        //...
        if TestRun {
                e.POST("/stop-test-server", func(ctx echo.Context) error {
                        StopTestServer <- true
                        return nil
                })
        }
        //…
}

As you can see within our main application, we flag the addition of a POST handler to the endpoint /stop-test-server that is handled by the anonymous function shown, which merely informs our test when it is time to stop the test server. This may seem silly, but now when we run the following command, the go test command starts up our main function and allows us to run external tests against it, and allows us to externally stop the processing of the tests which show us the coverage information for our handlers package:

go test ./cmd/service/ -v -coverpkg ./handlers -coverprofile cov.txt -run=TestRunMain
=== RUN   TestRunMain

   ____    __
  / __/___/ /  ___
 / _// __/ _ / _ 
/___/\__/_//_/\___/ v3.2.6
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O
⇨ http server started on [::]:8080

At this point, you are able to perform HTTP calls against this using external tools, such as curl seen here:

curl http://localhost:8080/health-check
{"message":"Everything is good!"}
curl -XPOST http://localhost:8080/stop-test-server

After performing these two curl commands, if you look at the output from your test run, you will notice that we get some logging information about the requests performed, as well as finally, the coverage information for our handler functions, which is pasted here:

--- PASS: TestRunMain (67.31s)
PASS
coverage: 7.9% of statements in ./handlers
ok      github.com/PacktPublishing/Echo-Essentials/chapter7/cmd/service    67.320s  coverage: 7.9% of statements in ./handlers

This capability will present real coverage numbers for our handlers package from external testing. External testing frameworks such as cucumber allow you to perform behavior driven testing with a fully featured framework that is not written in Go. This means you will be able to have team members, such as quality engineers write tests for your service in whatever framework they want to, and still get the coverage numbers for your code. As you can see here, with the coverage tool, you can even drill down and see individual function coverage numbers which can help with coverage reports:

go tool cover -func=cov.txt 

github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/err.go:10:               Error           0.0%
github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/health-check.go:13:      HealthCheck     100.0%
github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/login.go:19:             Login           0.0%
github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/logout.go:5:             Logout          0.0%
github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/reminder.go:5:           CreateReminder  0.0%
github.com/PacktPublishing/Echo-Essentials/chapter7/handlers/reminder.go:9:           GetReminder     0.0%
total:                                                          (statements)    7.9%

It is fairly easy to see how this could benefit an organization if implemented within a Continuous integration and Continuous Deployment pipeline. Tests do not need to be exclusively written in Go, and you can have real integration tested by running the instrumented test server next to a real database and other integrated systems.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.230.81