📖 Go Fiber by Examples: Testing the application
Tags: go, beginners, tutorial, testing
Published: 2021-08-30 11:10:55

## Introduction

Hey, DEV friends! 👋 

Today I'm going to share with you another chapter from my canceled book **Easy Development with GoFiber** (I talked about it in the [first article](https://dev.to/koddr/go-fiber-by-examples-how-can-the-fiber-web-framework-be-useful-487a) of this series). Actually, this chapter was supposed to be in the practical part of the book (_the article series_), but I purposely pulled it out as the third chapter.

I think application testing is just as important in understanding how the web framework works under the hood. 

## Plan for the Chapter 3

In this third article (or chapter), we will review the topic of the [Fiber](https://github.com/gofiber/fiber) application testing for beginners on real example. 

And we’re going to cover the following 👇

<a name="toc"></a>
### 📝 Table of contents

- [Reasons for testing](#reasons-for-testing)
- [What does the test function include?](#what-does-the-test-function-include)
- [Creating a test function](#creating-a-test-function)
  - [Tip for VS Code users](#tip-for-vs-code-users)
  - [Test code and detailed description](#test-code-and-detailed-description)
- [Summary](#summary)

<a name="#reasons-for-testing"></a>
## Reasons for testing

Testing written code is a very useful and needed skill, so we will start this article with a review of the **Fiber** application testing process. 

We will use both the features built into the language and the framework for testing and some third-party tools. For example, the very popular **Go** testing package [Testify](https://github.com/stretchr/testify).

> ☝️ **Note:** Don't worry if you've never written unit-tests in your **Go** applications, because it's a very easy process to understand!

[↑ Table of contents](#toc)

<a name="#what-does-the-test-function-include"></a>
## What does the test function include?

The test function is very similar to the usual **Go** function, but has only the purpose of checking the incoming conditions on strictly defined test cases. To avoid confusion between them, always add the `_test` suffix to the name of the test file, and begin the name of the test function itself with the word Test.

For example, if we need to cover the `SomeFuncToExample` function, which is in the `example.go` file, we need to create a new file named `example_text.go`, in which we need to place a test function named `TestSomeFuncToExample(t *testing.T)`.

> ☝️ **Note:** Also, note that the test file must be inside the same **Go** package as the function to be tested.

Typically, each test function contains:

- A structure that describes the incoming conditions.
- A collection of test cases, according to the structure.
- A test instance of an application with some simple state.
- A loop with test logic inside, to do an enumeration of test cases.

[↑ Table of contents](#toc)

<a name="#creating-a-test-function"></a>
## Creating a test function

Now, let's look at an example of such a test function on a very simple example: we're going to check one of the application paths for what HTTP methods it gives back.

If it gives a status of HTTP 200 OK, then this test case will be successful (_PASS_). In the case, if it will give a status of HTTP 404 Not Found, then it will fail. But we will be ready for this error.

Such a test case is needed to test our target function not only for a positive scenario, but also for a negative (_FAIL_) scenario, which may also occur as a result of using the application in the future.

[↑ Table of contents](#toc)

<a name="#tip-for-vs-code-users"></a>
### Tip for VS Code users

If you write code in [VS Code](https://code.visualstudio.com/) with the [Go tools](https://code.visualstudio.com/docs/languages/go) plugin (like me 😋), it has a built-in generator for unit-tests that generates a starting template for testing a particular function:

![VS Code unit-test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kgxyqsclrg9vbd84dfsx.png)

Click them and a template like this will be created:

![VS Code Go tools demo](https://code.visualstudio.com/assets/docs/languages/go/completion-signature-help.gif)

[↑ Table of contents](#toc)

<a name="#test-code-and-detailed-description"></a>
### Test code and detailed description

OK! Let's write our first unit-test. As always, please follow the comments in the code, it will help you understand what is going on in each of the lines.

```go
// ./go/testing.go

package routes

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

  "github.com/gofiber/fiber/v2"
  "github.com/stretchr/testify/assert" // add Testify package
)

func TestHelloRoute(t *testing.T) {
  // Define a structure for specifying input and output data
  // of a single test case
  tests := []struct {
    description  string // description of the test case
    route        string // route path to test
    expectedCode int    // expected HTTP status code
  }{
    // First test case
    {
      description:  "get HTTP status 200",
      route:        "/hello",
      expectedCode: 200,
    },
    // Second test case
    {
      description:  "get HTTP status 404, when route is not exists",
      route:        "/not-found",
      expectedCode: 404,
    },
  }

  // Define Fiber app.
  app := fiber.New()

  // Create route with GET method for test
  app.Get("/hello", func(c *fiber.Ctx) error {
    // Return simple string as response
    return c.SendString("Hello, World!")
  })

  // Iterate through test single test cases
  for _, test := range tests {
    // Create a new http request with the route from the test case
    req := httptest.NewRequest("GET", test.route, nil)

    // Perform the request plain with the app,
    // the second argument is a request latency
    // (set to -1 for no latency)
    resp, _ := app.Test(req, 1)

    // Verify, if the status code is as expected
    assert.Equalf(t, test.expectedCode, resp.StatusCode, test.description)
  }
}
```

Alright, now let's go into more detail only about the logic of the test function, which is in the for loop. The other parts of the test function should already be familiar to you from other sections of this article.

So, at the very beginning of the loop, using the standard **Go** package called [httptest](https://pkg.go.dev/net/http/httptest), we create a new HTTP request with the GET method to be sent to the routing address from the test case.

> ☝️ **Note:** It's the following line: `resp, _ := app.Test(req, 1)`. 

This passes the newly created HTTP request to the Test function built into the **Fiber** web framework, which we looked at earlier in this article. This is required so that the application instance can process the request.

The next step is to compare two HTTP statuses: the one obtained from the request and the one we specified in the test case. Here we first encounter the most frequently used function `assert.Equalf` from the **Testify** package, the purpose of which is simply to compare two values. If the values match completely, the test will be considered passed.

Running this test with the command `go test -v ./...`, we will see that test was successful:

```console
=== RUN   TestHelloRoute
--- PASS: TestHelloRoute (0.00s)
```

Congratulations! 🎉 We just wrote a unit-test for a function, and it succeeded. Yes, that was just one use case, but trust me, the same thing is waiting in real applications.

We will see it for ourselves in the next parts of this series.

[↑ Table of contents](#toc)

<a name="#summary"></a>
## Summary

We wrote our first test case for the application, using the `Test` method and the third-party package called **Testify**. I truly hope that now it will be much easier for you to write tests for your **Fiber** (_and not only_) web applications!

In the next article, we will be working with internal and external **Fiber** middleware, third-party packages and boilerplate.

[↑ Table of contents](#toc)

<a name=""></a>
## Photos and videos by

- Clint McKoy https://unsplash.com/photos/App9lCSl2uA
- Go Team at Google https://code.visualstudio.com/docs/languages/go

<a name=""></a>
## P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

- 🔥 [gowebly][gowebly_url]: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
- ✨ [create-go-app][cgapp_url]: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
- 🏃 [yatr][yatr_url]: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
- 📚 [gosl][gosl_url]: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
- 🏄‍♂️ [csv2api][csv2api_url]: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
- 🚴 [json2csv][json2csv_url]: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

<!-- Footer links -->

[gowebly_url]: https://github.com/gowebly
[cgapp_url]: https://github.com/create-go-app
[yatr_url]: https://github.com/koddr/yatr
[gosl_url]: https://github.com/koddr/gosl
[csv2api_url]: https://github.com/koddr/csv2api
[json2csv_url]: https://github.com/koddr/json2csv