All Projects → Eun → go-hit

Eun / go-hit

Licence: MIT License
http integration test framework

Programming Languages

go
31211 projects - #10 most used programming language
Makefile
30231 projects

go-hit

Actions Status Coverage Status PkgGoDev GoDoc go-report go1.15

hit is an http integration test framework written in golang.

It is designed to be flexible as possible, but to keep a simple to use interface for developers.

So lets get started!

go get -u github.com/Eun/go-hit

package main

import (
    "net/http"
    . "github.com/Eun/go-hit"
)

func main() {
    MustDo(
        Description("Post to httpbin.org"),
        Get("https://httpbin.org/post"),
        Expect().Status().Equal(http.StatusMethodNotAllowed),
        Expect().Body().String().Contains("Method Not Allowed"),
    )
}

Or use the Test() function:

package main_test
import (
    "testing"
    "net/http"
    . "github.com/Eun/go-hit"
)

func TestHttpBin(t *testing.T) {
    Test(t,
        Description("Post to httpbin.org"),
        Get("https://httpbin.org/post"),
        Expect().Status().Equal(http.StatusMethodNotAllowed),
        Expect().Body().String().Contains("Method Not Allowed"),
    )
}

Expect, Expect, Expect, ....

MustDo(
    Get("https://httpbin.org/post"),
    Expect().Status().Equal(http.StatusMethodNotAllowed),
    Expect().Headers("Content-Type").NotEmpty(),
    Expect().Body().String().Contains("Method Not Allowed"),
)

Sending Data

MustDo(
    Post("https://httpbin.org/post"),
    Send().Body().String("Hello HttpBin"),
    Expect().Status().Equal(http.StatusOK),
    Expect().Body().String().Contains("Hello HttpBin"), 
)

Sending And Expecting JSON

MustDo(
    Post("https://httpbin.org/post"),
    Send().Headers("Content-Type").Add("application/json"),
    Send().Body().JSON(map[string][]string{"Foo": []string{"Bar", "Baz"}}),
    Expect().Status().Equal(http.StatusOK),
    Expect().Body().JSON().JQ(".json.Foo[1]").Equal("Baz"),
)

Storing Data From The Response

var name string
var roles []string
MustDo(
    Post("https://httpbin.org/post"),
    Send().Headers("Content-Type").Add("application/json"),
    Send().Body().JSON(map[string]interface{}{"Name": "Joe", "Roles": []string{"Admin", "Developer"}}),
    Expect().Status().Equal(http.StatusOK),
    Store().Response().Body().JSON().JQ(".json.Name").In(&name),
    Store().Response().Body().JSON().JQ(".json.Roles").In(&roles),
)
fmt.Printf("%s has %d roles\n", name, len(roles))

Problems? Debug!

MustDo(
    Post("https://httpbin.org/post"),
    Debug(),
    Debug().Response().Body(),
)

Handling Errors

It is possible to handle errors in a custom way.

func login(username, password string) error {
    err := Do(
         Get("https://httpbin.org/basic-auth/joe/secret"),
         Send().Headers("Authorization").Add("Basic " + base64.StdEncoding.EncodeToString([]byte(username + ":" + password))),
         Expect().Status().Equal(http.StatusOK),
    )
    var hitError *Error
    if errors.As(err, &hitError) {
        if hitError.FailingStepIs(Expect().Status().Equal(http.StatusOK)) {
            return errors.New("login failed")
        }
    }
    return err
}

Build the request url manually

MustDo(
    Request().Method(http.MethodPost),
    Request().URL().Scheme("https"),
    Request().URL().Host("httpbin.org"),
    Request().URL().Path("/post"),
    Request().URL().Query("page").Add(1),
    Expect().Status().Equal(200),
    Send().Body().String("Hello World"),
    Expect().Body().String().Contains("Hello"),
)

Twisted!

Although the following is hard to read it is possible to do!

MustDo(
    Post("https://httpbin.org/post"),
    Expect().Status().Equal(200),
    Send().Body().String("Hello World"),
    Expect().Body().String().Contains("Hello"),
)

Custom Send And Expects

MustDo(
    Get("https://httpbin.org/get"),
    Send().Custom(func(hit Hit) error {
        hit.Request().Body().SetStringf("Hello %s", "World")
        return nil
    }),
    Expect().Custom(func(hit Hit) error {
        if len(hit.Response().Body().MustString()) <= 0 {
            return errors.New("expected the body to be not empty")
        }
        return nil
    }),
    Custom(AfterExpectStep, func(Hit) error {
        fmt.Println("everything done")
        return nil
    }),
)

Templates / Multiuse

template := CombineSteps(
    Post("https://httpbin.org/post"),
    Send().Headers("Content-Type").Add("application/json"),
    Expect().Headers("Content-Type").Equal("application/json"),
)
MustDo(
    template,
    Send().Body().JSON("Hello World"),
)

MustDo(
    template,
    Send().Body().JSON("Hello Universe"),
)

Clean Previous Steps

Sometimes it is necessary to remove some steps that were added before.

template := CombineSteps(
    Get("https://httpbin.org/basic-auth/joe/secret"),
    Expect().Status().Equal(http.StatusOK),
)
MustDo(
    Description("login with correct credentials"),
    template,
    Send().Headers("Authorization").Add("Basic " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))),
)

Test(t,
    Description("login with incorrect credentials"),
    template,
    Clear().Expect().Status(),
    Expect().Status().Equal(http.StatusUnauthorized),
    Send().Headers("Authorization").Add("Basic " + base64.StdEncoding.EncodeToString([]byte("joe:joe"))),
)

More examples can be found in the examples directory

Changelog

0.5.0

  • Rehaul the api, make things more explicit
  • Fix some issues
  • Store() functionality
  • Generate Clear() paths
  • Infinite JQ() functionality
  • Test README.md and documentation parts

0.4.0

  • Fixed a double run bug in CombineSteps (#3)
  • Better Clear functionality, you can now clear any previous step by prepending Clear(), eg.
    Do(
        Get("https://example.com"),
        Expect().Body("Hello World"),
        Clear().Expect(),                        // remove all previous Expect() steps
        // Clear().Expect().Body("Hello World"), // remove only the Expect().Body("Hello World") step
    )
    
    // also works for CombineSteps
    Do(
        Post("https://example.com"),        
        CombineSteps(
            Send().Body().String("Hello World"),
            Expect().Body("Hello World"),
        ),
        Clear().Expect(),
    )
  • Simplified Expect().Header() use, no more Expect().Headers(), everything can now be done in the Expect().Header() function.
  • More documentation and examples
  • hit.Do and hit.MustDo for inline steps.
  • Removal of inline steps (use hit.Do and hit.MustDo)
    Do(
        Get("https://example.com"),
        Expect().Custon(func (hit Hit) {
            // Expect("Hello World") is invalid now
            // you must use MustDo() or Do()
            hit.MustDo(
                Expect("Hello World"),
            )
        }),
    )
  • hit.InsertSteps to insert steps during runtime
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].