DEV Community

Discussion on: Writing cleaner Go web servers

Collapse
 
maxatome profile image
Maxime Soulé • Edited

Hi, nice work!

I see that testing is on your todo list, let me introduce you go-testdeep and its tdhttp package: it makes the tests very easy.

Just define first if you want to use Mongo during tests or not. If yes, perhaps a Mongo instance should be launched during the tests (in a docker for example) or it can be mocked behind an interface. If no, one should be able to disable it during tests and use only memory DB.

Then:

package server_test

import (
    "fmt"
    "net/http"
    "testing"

    "github.com/maxatome/go-testdeep/helpers/tdhttp"
    "github.com/maxatome/go-testdeep/td"

    "github.com/chidiwilliams/go-web-server-tips/models"
    "github.com/chidiwilliams/go-web-server-tips/server"
)

func TestRoutes(t *testing.T) {
    ta := tdhttp.NewTestAPI(t, server.Server().Handler)

    var bookID int64
    ta.PostJSON("/book", models.Book{Title: "My First Book"}).
        Name("Create a new book").
        CmpStatus(http.StatusOK).
        CmpJSONBody(
            td.JSON(`{"book": {"id": $1, "title": "My First Book", "created_at": $2} }`,
                td.Catch(&bookID, td.NotZero()), // we don't know the ID in advance, but here it should not be 0 and we want to capture it
                td.Not(td.Re(`^0001-01-01`)),    // time is not 0001-01-01… aka zero time.Time
            ))

    ta.Get(fmt.Sprintf("/book/%d", bookID)).
        Name("Get an existing book").
        CmpStatus(http.StatusOK).
        CmpJSONBody(
            td.JSON(`{"book": {"id": $1, "title": "My First Book", "created_at": $2} }`,
                bookID,                       // now we know it
                td.Not(td.Re(`^0001-01-01`)), // note the test can be much more complex, see td docs
            ))
}

td.JSON is an operator among 60 other, like td.Not, td.Re, td.NotZero or td.Catch. See other operators.

I did not test the code above, but I am pretty sure you get the point :)

Enjoy your tests!