How to Create Integration Tests in Golang
Carrying out integration tests for APIs means that we must at least be able to run the application first so that integrated testing can be carried out.
We need to prepare several cases, test cases that cover the needs of the integration test. For example, the API Endpoint' that we have worked on has a database, cache` or other external resource that is related to the continuity of the API Endpoint.
So, we will simulate how to carry out an API integration test. The first stage is that we create an API Service where the API is used for number addition operations.
Create API Programs
The following is the API Endpoint program that will be tested or an integration test will be created.
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "net/http"
7 "strconv"
8)
9
10func main() {
11 http.HandleFunc("/add", HandleAddInts)
12 address := ":9000"
13 fmt.Printf("Memulai server at %s\n", address)
14 fmt.Println()
15 fmt.Println("contoh query: /add?a=2&b=2&authtoken=abcdef123")
16 fmt.Println("tokennya adalah 'abcdef123'")
17 err := http.ListenAndServe(address, nil)
18 if err != nil {
19 fmt.Printf("error ketika start server: %v", err)
20 }
21}
22
23type TambahResponse struct {
24 Result int `json:"result"`
25}
26
27func HandleAddInts(w http.ResponseWriter, r *http.Request) {
28 params := r.URL.Query()
29 paramA := params.Get("a")
30 paramB := params.Get("b")
31 token := params.Get("authtoken")
32
33 if paramA == "" || paramB == "" || token == "" {
34 http.Error(w, "tidak ada parameters", http.StatusBadRequest)
35 return
36 }
37
38 if token != "abcdef123" {
39 http.Error(w, "token tidak valid", http.StatusUnauthorized)
40 return
41 }
42
43 intA, err := strconv.Atoi(paramA)
44 if err != nil {
45 http.Error(w, "parameter 'a' harus integer", http.StatusBadRequest)
46 return
47 }
48
49 intB, err := strconv.Atoi(paramB)
50 if err != nil {
51 http.Error(w, "parameter 'b' harus integer", http.StatusBadRequest)
52 return
53 }
54
55 response := TambahResponse{
56 Result: intA + intB,
57 }
58
59 json, err := json.MarshalIndent(&response, "", " ")
60 if err != nil {
61 http.Error(w, "error while marshalling", http.StatusInternalServerError)
62 return
63 }
64
65 fmt.Fprint(w, string(json))
66}In this program there are several validations when the program is run, namely * The parameters entered must be integer
- Do not fill in the parameters
aandbthen it will become - Test if it doesn’t send
authToken
After the above program is complete, we run it with the command
1➜ integration-test git:(main) ✗ go run app/main.go
2Memulai server at :9000
3
4contoh query: /add?a=2&b=2&authtoken=abcdef123
5tokennya adalah 'abcdef123'If the program has run successfully, it will be visible or can be accessed using postman and curl with endpoint and port :9000.
1➜ materi curl 'http://localhost:9000/add?a=2&b=2&authtoken=abcdef123'
2{
3 "result": 4
4}% If the program is successful as above then, we have run the API program to add numbers using the http protocol.
Create Integration Tests
Next, we will create an API integration test that we created earlier with several cases mentioned above.
Prepare the program or file main.go to create API Testing.
1package integrationtest
2
3import (
4 "encoding/json"
5 "fmt"
6 "io/ioutil"
7 "net/http"
8)
9
10type MathClient struct {
11 Token string
12 Host string
13}
14
15type AddResult struct {
16 Result int `json:"result"`
17}
18
19func (c *MathClient) APISum(i, j int) (int, error) {
20 query := fmt.Sprintf("http://%s/add?a=%v&b=%v&authtoken=%v", c.Host, i, j, c.Token)
21
22 response, err := http.Get(query)
23 if err != nil {
24 return 0, err
25 }
26 defer response.Body.Close()
27
28 data, err := ioutil.ReadAll(response.Body)
29 if err != nil {
30 return 0, err
31 }
32
33 a := AddResult{}
34 err = json.Unmarshal(data, &a)
35 if err != nil {
36 return 0, err
37 }
38
39 return a.Result, nil
40}We will use the APISum method to access the http API that we have created as the main server which we will test using this integration test.
Create Client Struct
Create a struct for the API structure and response like this.
1type MathClient struct {
2 Token string
3 Host string
4}
5
6type AddResult struct {
7 Result int `json:"result"`
8}Create a Sum API Access Method
then we will create a method to retrieve the API sum data.
1func (c *MathClient) APISum(i, j string) (int, int, error) {
2 query := fmt.Sprintf("http://%s/add?a=%s&b=%s&authtoken=%v", c.Host, i, j, c.Token)
3
4 var statusCode int = http.StatusBadRequest
5 response, err := http.Get(query)
6 if err != nil {
7 return 0, statusCode, err
8 }
9 defer response.Body.Close()
10 statusCode = response.StatusCode
11 data, err := ioutil.ReadAll(response.Body)
12 if err != nil {
13 return 0, statusCode, err
14 }
15
16 a := AddResult{}
17 err = json.Unmarshal(data, &a)
18 if err != nil {
19 return 0, statusCode, err
20 }
21
22 return a.Result, statusCode, nil
23}Create a Unit Test which is used as an Integration Test
Next, we will create this API Integration testing in this method. We can make a program like this or just generate in the APISum method.
1func TestMathClient_APISum(t *testing.T) {
2 type fields struct {
3 Token string
4 Host string
5 }
6 type args struct {
7 i string
8 j string
9 }
10 tests := []struct {
11 name string
12 fields fields
13 args args
14 want int
15 wantErr bool
16 wantCode int
17 }{
18 // testing test case
19 }
20 for _, tt := range tests {
21 t.Run(tt.name, func(t *testing.T) {
22 c := &MathClient{
23 Token: tt.fields.Token,
24 Host: tt.fields.Host,
25 }
26 got, gotCode, err := c.APISum(tt.args.i, tt.args.j)
27 if (err != nil) != tt.wantErr {
28 t.Errorf("MathClient.APISum() error = %v, wantErr %v", err, tt.wantErr)
29 return
30 }
31 if got != tt.want {
32 t.Errorf("MathClient.APISum() = %v, want %v", gotCode, tt.wantCode)
33 }
34 if gotCode != tt.wantCode {
35 t.Errorf("MathClient.APISum() = %v, want %v", gotCode, tt.wantCode)
36 }
37 })
38 }
39}Add Test Cases
Then, so that we can carry out case by case testing, we need to fill in the number of cases in the curly brackets above with contents like this.
1{
2 name: "case sukses jumlah data",
3 fields: fields{
4 Token: "abcdef123",
5 Host: "localhost:9000",
6 },
7 args: args{
8 i: "2",
9 j: "2",
10 },
11 want: 4,
12 wantErr: false,
13 wantCode: http.StatusOK,
14},
15{
16 name: "token tidak diset",
17 fields: fields{
18 Token: "abc",
19 Host: "localhost:9000",
20 },
21 args: args{
22 i: "2",
23 j: "2",
24 },
25 want: 0,
26 wantErr: true,
27 wantCode: http.StatusUnauthorized,
28},
29{
30 name: "host tidak sesuai",
31 fields: fields{
32 Token: "abcdef123",
33 Host: "localhost:500",
34 },
35 args: args{
36 i: "2",
37 j: "2",
38 },
39 want: 0,
40 wantErr: true,
41 wantCode: http.StatusBadRequest,
42},
43{
44 name: "case parameter kosong",
45 fields: fields{
46 Token: "abcdef123",
47 Host: "localhost:9000",
48 },
49 args: args{
50 i: "",
51 j: "",
52 },
53 want: 0,
54 wantErr: true,
55 wantCode: http.StatusBadRequest,
56},
57{
58 name: "case parameter bukan integer",
59 fields: fields{
60 Token: "abcdef123",
61 Host: "localhost:9000",
62 },
63 args: args{
64 i: "a",
65 j: "a",
66 },
67 want: 0,
68 wantErr: true,
69 wantCode: http.StatusBadRequest,
70},Run Integration Test
Everything has been completed for testing and creating tests. Don’t forget that because this is integration test code, we need to add something so that when we do go test -v we can add the code above like this.
1//go:build integrationWe continue by running go test with the integration parameter
1$ go test -v -tags=integrationAlso make sure the API Endpoint program is running
1➜ integration-test git:(main) ✗ go run app/main.go
2Memulai server at :9000
3
4contoh query: /add?a=2&b=2&authtoken=abcdef123
5tokennya adalah 'abcdef123'