Introduction

Today, I’ll show you how I set up a simple test for WebSocket using gorilla/websocket in Echo framework and how it makes me more confident with my code 😄

Let’s get started

Writing a simple handler

The handler just simply says hello to the client (Hello, Client!) and reads the message from the client.

// websocket.go

package websocket

import (
  "fmt"

  "github.com/gorilla/websocket"
  "github.com/labstack/echo"
)

var (
  upgrader = websocket.Upgrader{}
)

func hello(c echo.Context) error {
  ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
  if err != nil {
    return err
  }
  defer ws.Close()

  for {
    // Write
    err := ws.WriteMessage(websocket.TextMessage, []byte("Hello, Client!"))
    if err != nil {
      c.Logger().Error(err)
    }

    // Read
    _, msg, err := ws.ReadMessage()
    if err != nil {
      c.Logger().Error(err)
    }
    fmt.Printf("%s\n", msg)
  }
}

Implement test

Because we need to communicate with WebSocket server so we need to create a test server by using httptest package, below is the handler function need for creating new test server:

type WsHandler struct {
  handler echo.HandlerFunc
}

func (h *WsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  e := echo.New()
  c := e.NewContext(r, w)

  forever := make(chan struct{})
  h.handler(c)
  <-forever
}
  1. Call the actual Echo handler function.
  2. Block, keep the handler function run forever.

This is full test file:

// websocket_test.go

package websocket

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

  "github.com/gorilla/websocket"
  "github.com/labstack/echo"
  "github.com/stretchr/testify/assert"
)

// WsHandler -
type WsHandler struct {
  handler echo.HandlerFunc
}

func (h *WsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  e := echo.New()
  c := e.NewContext(r, w)

  forever := make(chan struct{})
  h.handler(c)
  <-forever
}

func TestWebsocketExample(t *testing.T) {
  h := WsHandler{handler: hello}
  server := httptest.NewServer(http.HandlerFunc(h.ServeHTTP))
  defer server.Close()

  wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "/ws"
  ws, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
  assert.Nil(t, err, err)

  // write
  err = ws.WriteMessage(websocket.TextMessage, []byte("Hello, Server!"))
  assert.Nil(t, err, err)

  // read
  _, msg, err := ws.ReadMessage()
  assert.Nil(t, err, err)
  assert.Equal(t, "Hello, Client!", string(msg))
}

Source code

Source code for this test recipe can be found here.

Conclusion

That’s it! We have done a simple test case that ensures client and server receive hello from each other. And I want to say it is important to write tests for your real-world projects to get those benefits:

  • More confident.
  • More time to focus on new features.
  • Reduce bugs.
  • Easier for debugging.