« Back to Index

Testing Go Web Applications http://www.meetspaceapp.com/2016/05/16/acceptance-testing-go-webapps-with-cookies.html

View original Gist on GitHub

1. main.go

// package main is used here just for ease of running the demo.
// In reality, this would be package app
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
)

// App is our Application's base http.Handler
type App struct {
	*http.ServeMux
}

// NewApp constructs a new App and initializes our routing
func NewApp() *App {
	mux := http.NewServeMux()
	app := &App{mux}
	mux.HandleFunc("/", app.Root)
	return app
}

// Root is the root page of our application
func (a *App) Root(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello!")
}

var port = flag.Int("port", 8080, "Port to serve on")

func main() {
	flag.Parse()
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), NewApp()))
}

2. main_test.go

func TestAppRoot(t *testing.T) {
	app := NewApp()
	server := httptest.NewServer(app)
	defer server.Close()

	resp, err := http.Get(server.URL + "/")
	if err != nil {
		t.Error(err)
	}

	buf := &bytes.Buffer{}
	buf.ReadFrom(resp.Body)
	if strings.Index(buf.String(), "Hello!") == -1 {
		t.Error("Root should say hello")
	}
}
// Root is the root page of our application
func (a *App) Root(w http.ResponseWriter, r *http.Request) {
	var name string

	nameCookie, err := r.Cookie("name")
	if err == nil {
		name = nameCookie.Value
	} else if err != http.ErrNoCookie {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	t := template.Must(template.New("root").Parse(`
	<!doctype html>
	<html>
	<head><title>greeter</title></head>
	<body>
	{{if .}}
	  <h1>Hi {{.}}!</h1>
	{{else}}
	  <h1>Welcome! Who are you?</h1>
	  <form method="POST" action="/name">
	    <input type="text" placeholder="Your name" name="name">
	    <input type="submit" value="Set Name">
	  </form>
	{{end}}
	</body>
	</html>
	`))
	if err := t.Execute(w, name); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// NewApp constructs a new App and initializes our routing
func NewApp() *App {
	mux := http.NewServeMux()
	app := &App{mux}
	mux.HandleFunc("/", app.Root)
	mux.HandleFunc("/name", app.SetName) // <- NEW
	return app
}

func (a *App) SetName(w http.ResponseWriter, r *http.Request) {
	http.SetCookie(w, &http.Cookie{
		Name:     "name",
		Value:    r.FormValue("name"),
		HttpOnly: true,
		Expires:  time.Now().Add(24 * 14 * time.Hour),
	})
	http.Redirect(w, r, "/", http.StatusFound)
}
func TestSetName(t *testing.T) {
	app := NewApp()
	server := httptest.NewServer(app)
	defer server.Close()

	jar, err := cookiejar.New(nil)
	if err != nil {
		t.Error(err)
	}
	client := &http.Client{Jar: jar}

	resp, err := client.Get(server.URL + "/")
	if err != nil {
		t.Error(err)
	}

	buf := &bytes.Buffer{}
	buf.ReadFrom(resp.Body)
	if strings.Index(buf.String(), "Welcome") == -1 {
		t.Errorf("Root should say Welcome!:\n%s", buf.String())
	}

	resp, err = client.PostForm(
        	server.URL+"/name",
        	url.Values{"name": {"Nick"}},
        )
	if err != nil {
		t.Error(err)
	}

	buf.Reset()
	buf.ReadFrom(resp.Body)
	if strings.Index(buf.String(), "Hi Nick!") == -1 {
		t.Errorf("Root should say Hi Nick!:\n%s", buf.String())
	}
}