Documentation ¶
Overview ¶
Package http helps with end-to-end HTTP and REST API testing.
Usage examples ¶
See example directory:
Communication mode ¶
There are two common ways to test API with http:
- start HTTP server and instruct http to use HTTP client for communication
- don't start server and instruct http to invoke http handler directly
The second approach works only if the server is a Go module and its handler can be imported in tests.
Concrete behaviour is determined by Client implementation passed to Config struct. If you're using http.Client, set its Transport field (http.RoundTriper) to one of the following:
- default (nil) - use HTTP transport from net/http (you should start server)
- http.Binder - invoke given http.Handler directly
- http.FastBinder - invoke given fasthttp.RequestHandler directly
Note that http handler can be usually obtained from http framework you're using. E.g., echo framework provides either http.Handler or fasthttp.RequestHandler.
You can also provide your own implementation of RequestFactory (creates http.Request), or Client (gets http.Request and returns http.response).
If you're starting server from tests, it's very handy to use net/http/httptest.
Value equality ¶
Whenever values are checked for equality in http, they are converted to "canonical form":
- structs are converted to map[string]interface{}
- type aliases are removed
- numeric types are converted to float64
- non-nil interfaces pointing to nil slices and maps are replaced with nil interfaces
This is equivalent to subsequently json.Marshal() and json.Unmarshal() the value and currently is implemented so.
Failure handling ¶
When some check fails, failure is reported. If non-fatal failures are used (see Reporter interface), execution is continued and instance that was checked is marked as failed.
If specific instance is marked as failed, all subsequent checks are ignored for this instance and for any child instances retrieved after failure.
Example:
array := NewArray(NewAssertReporter(t), []interface{}{"foo", 123}) e0 := array.Element(0) // success e1 := array.Element(1) // success s0 := e0.String() // success s1 := e1.String() // failure; e1 and s1 are marked as failed, e0 and s0 are not s0.Equal("foo") // success s1.Equal("bar") // this check is ignored because s1 is marked as failed
Index ¶
- Constants
- func New(baseURL string) *expect
- func WithConfig(config Config) *expect
- type Client
- type Config
- type Request
- func (r *Request) Expect() *response
- func (r *Request) LastError() error
- func (r *Request) WithAccept(accept string) *Request
- func (r *Request) WithAcceptEncoding(acceptEncoding string) *Request
- func (r *Request) WithAcceptLanguage(acceptLanguage string) *Request
- func (r *Request) WithAuthorization(authorization string) *Request
- func (r *Request) WithBasicAuth(username, password string) *Request
- func (r *Request) WithBearerToken(token string) *Request
- func (r *Request) WithBytes(b []byte) *Request
- func (r *Request) WithChunked(reader io.Reader) *Request
- func (r *Request) WithClient(client Client) *Request
- func (r *Request) WithConnection(connection string) *Request
- func (r *Request) WithContentType(contentType string) *Request
- func (r *Request) WithCookie(k, v string) *Request
- func (r *Request) WithCookies(cookies map[string]string) *Request
- func (r *Request) WithFile(key, path string, reader ...io.Reader) *Request
- func (r *Request) WithFileBytes(key, path string, data []byte) *Request
- func (r *Request) WithForm(object interface{}) *Request
- func (r *Request) WithFormField(key string, value interface{}) *Request
- func (r *Request) WithFunc(f func(req *Request) *Request) *Request
- func (r *Request) WithHeader(k, v string) *Request
- func (r *Request) WithHeaders(headers map[string]string) *Request
- func (r *Request) WithHttpCookie(cookies ...*http.Cookie) *Request
- func (r *Request) WithJSON(object interface{}) *Request
- func (r *Request) WithKeepAlive() *Request
- func (r *Request) WithMultiHeaders(headers map[string][]string) *Request
- func (r *Request) WithMultipart() *Request
- func (r *Request) WithPath(key string, value interface{}) *Request
- func (r *Request) WithProto(proto string) *Request
- func (r *Request) WithQuery(key string, value interface{}) *Request
- func (r *Request) WithQueryString(query string) *Request
- func (r *Request) WithReferer(ref string) *Request
- func (r *Request) WithText(s string) *Request
- func (r *Request) WithURL(urlStr string) *Request
- func (r *Request) WithUserAgent(userAgent string) *Request
- func (r *Request) WithXMLHttpRequest() *Request
- func (r *Request) WithXRequestedWith(requestedWith string) *Request
- type RequestFactory
Constants ¶
const ( MIMEJSON = "application/json" MIMEHTML = "text/html" MIMEXML = "application/xml" MIMEXML2 = "text/xml" MIMEPlain = "text/plain" MIMEPOSTForm = "application/x-www-form-urlencoded" MIMEMultipartPOSTForm = "multipart/form-data" MIMEPROTOBUF = "application/x-protobuf" MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK2 = "application/msgpack" MIMEYAML = "application/x-yaml" )
Variables ¶
This section is empty.
Functions ¶
func New ¶
func New(baseURL string) *expect
New returns a new expect object.
baseURL specifies URL to prepended to all Request. My be empty. If non-empty, trailing slash is allowed but not required and is appended automatically.
New is a shorthand for WithConfig. It uses:
- CompactPrinter as Printer, with testing.TB as Logger
- AssertReporter as Reporter
- defaultRequestFactory as RequestFactory
Client is set to a default client with a non-nil Jar:
&http.Client{ Jar: http.NewJar(), }
Example:
func TestSomething(t *testing.T) { e := http.New(t, "http://example.com/") e.GET("/path"). expect(). Status(http.StatusOK) }
func WithConfig ¶
func WithConfig(config Config) *expect
WithConfig returns a new expect object with given config.
If RequestFactory is nil, it's set to a defaultRequestFactory instance.
If Client is nil, it's set to a default client with a non-nil Jar:
&http.Client{ Jar: http.NewJar(), }
Example:
func TestWithConfig(t *testing.T) { e := http.WithConfig(http.Config{ BaseURL: "http://example.com/", Client: &http.Client{ Transport: http.NewBinder(myHandler()), Jar: http.NewJar(), }, }) e.GET("/path"). expect(). Status(http.StatusOK) }
Types ¶
type Client ¶
type Client interface { // Do sends Request and returns response. Do(*http.Request) (*http.Response, error) }
Client is used to send http.Request and receive http.response. http.Client implements this interface.
Binder and FastBinder may be used to obtain this interface implementation.
Example:
httpBinderClient := &http.Client{ Transport: http.NewBinder(HTTPHandler), } fastBinderClient := &http.Client{ Transport: http.NewFastBinder(FastHTTPHandler), }
type Config ¶
type Config struct { // BaseURL is a URL to prepended to all Request. My be empty. If // non-empty, trailing slash is allowed but not required and is // appended automatically. BaseURL string // RequestFactory is used to pass in a custom *http.Request generation func. // May be nil. // // You can use defaultRequestFactory, or provide custom implementation. // Useful for Google App Engine testing for example. RequestFactory RequestFactory // Client is used to send http.Request and receive http.response. // Should not be nil. // // You can use http.DefaultClient or http.Client, or provide // custom implementation. Client Client }
Config contains various settings.
type Request ¶
type Request struct {
// contains filtered or unexported fields
}
Request provides methods to incrementally build http.Request object, send it, and receive response.
func (*Request) Expect ¶
func (r *Request) Expect() *response
expect constructs http.Request, sends it, receives http.response, and returns a new response object to inspect received response.
Request is sent using Config.Client interface, or Config.Dialer interface in case of WebSocket Request.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithJSON(map[string]interface{}{"foo": 123}) resp := req.expect() resp.Status(http.StatusOK)
func (*Request) WithAcceptEncoding ¶
func (*Request) WithAcceptLanguage ¶
func (*Request) WithAuthorization ¶
func (*Request) WithBasicAuth ¶
WithBasicAuth sets the Request's Authorization header to use HTTP Basic Authentication with the provided username and password.
With HTTP Basic Authentication the provided username and password are not encrypted.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithBasicAuth("john", "secret")
func (*Request) WithBytes ¶
WithBytes sets Request body to given slice of bytes.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithHeader("Content-Type": "application/json") req.WithBytes([]byte(`{"foo": 123}`))
func (*Request) WithChunked ¶
WithChunked enables chunked encoding and sets Request body reader.
expect() will read all available data from given reader. Content-Length is not set, and "chunked" Transfer-Encoding is used.
If protocol version is not at least HTTP/1.1 (required for chunked encoding), failure is reported.
Example:
req := NewRequest(config, "PUT", "http://example.com/upload") fh, _ := os.Open("data") defer fh.Close() req.WithHeader("Content-Type": "application/octet-stream") req.WithChunked(fh)
func (*Request) WithClient ¶
WithClient sets client.
The new client overwrites Config.Client. It will be used once to send the Request and receive a response.
Example:
req := NewRequest(config, "GET", "/path") req.WithClient(&http.Client{ Transport: &http.Transport{ DisableCompression: true, }, })
func (*Request) WithCookie ¶
WithCookie adds given single cookie to Request.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithCookie("name", "value")
func (*Request) WithCookies ¶
WithCookies adds given cookies to Request.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithCookies(map[string]string{ "foo": "aa", "bar": "bb", })
func (*Request) WithFile ¶
WithFile sets Content-Type header to "multipart/form-data", reads given file and adds its contents to Request body.
If reader is given, it's used to read file contents. Otherwise, os.Open() is used to read a file with given path.
Multiple WithForm(), WithFormField(), and WithFile() calls may be combined. WithMultipart() should be called before WithFile(), otherwise WithFile() fails.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithFile("avatar", "./john.png") req := NewRequest(config, "PUT", "http://example.com/path") fh, _ := os.Open("./john.png") req.WithMultipart(). WithFile("avatar", "john.png", fh) fh.Close()
func (*Request) WithFileBytes ¶
WithFileBytes is like WithFile, but uses given slice of bytes as the file contents.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") fh, _ := os.Open("./john.png") b, _ := ioutil.ReadAll(fh) req.WithMultipart(). WithFileBytes("avatar", "john.png", b) fh.Close()
func (*Request) WithForm ¶
WithForm sets Content-Type header to "application/x-www-form-urlencoded" or (if WithMultipart() was called) "multipart/form-data", converts given object to url.Values using github.com/ajg/form, and adds it to Request body.
Various object types are supported, including maps and structs. Structs may contain "form" struct tag, similar to "json" struct tag for json.Marshal(). See https://github.com/ajg/form for details.
Multiple WithForm(), WithFormField(), and WithFile() calls may be combined. If WithMultipart() is called, it should be called first.
Example:
type MyForm struct { Foo int `form:"foo"` } req := NewRequest(config, "PUT", "http://example.com/path") req.WithForm(MyForm{Foo: 123}) req := NewRequest(config, "PUT", "http://example.com/path") req.WithForm(map[string]interface{}{"foo": 123})
func (*Request) WithFormField ¶
WithFormField sets Content-Type header to "application/x-www-form-urlencoded" or (if WithMultipart() was called) "multipart/form-data", converts given value to string using fmt.Sprint(), and adds it to Request body.
Multiple WithForm(), WithFormField(), and WithFile() calls may be combined. If WithMultipart() is called, it should be called first.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithFormField("foo", 123). WithFormField("bar", 456)
func (*Request) WithFunc ¶
WithFunc can set any value with customer func
func (*Request) WithHeader ¶
WithHeader adds given single header to Request.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithHeader("Content-Type": "application/json")
func (*Request) WithHeaders ¶
WithHeaders adds given headers to Request.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithHeaders(map[string]string{ "Content-Type": "application/json", })
func (*Request) WithJSON ¶
WithJSON sets Content-Type header to "application/json; charset=utf-8" and sets body to object, marshaled using json.Marshal().
Example:
type MyJSON struct { Foo int `json:"foo"` } req := NewRequest(config, "PUT", "http://example.com/path") req.WithJSON(MyJSON{Foo: 123}) req := NewRequest(config, "PUT", "http://example.com/path") req.WithJSON(map[string]interface{}{"foo": 123})
func (*Request) WithMultiHeaders ¶
func (*Request) WithMultipart ¶
WithMultipart sets Content-Type header to "multipart/form-data".
After this call, WithForm() and WithFormField() switch to multipart form instead of urlencoded form.
If WithMultipart() is called, it should be called before WithForm(), WithFormField(), and WithFile().
WithFile() always requires WithMultipart() to be called first.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithMultipart(). WithForm(map[string]interface{}{"foo": 123})
func (*Request) WithPath ¶
WithPath substitutes named parameters in url path.
value is converted to string using fmt.Sprint(). If there is no named parameter '{key}' in url path, failure is reported.
Named parameters are case-insensitive.
Example:
req := NewRequest(config, "POST", "/repos/{user}/{repo}") req.WithPath("user", "gavv") req.WithPath("repo", "http") // path will be "/repos/gavv/http"
func (*Request) WithProto ¶
WithProto sets HTTP protocol version.
proto should have form of "HTTP/{major}.{minor}", e.g. "HTTP/1.1".
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithProto("HTTP/2.0")
func (*Request) WithQuery ¶
WithQuery adds query parameter to Request URL.
value is converted to string using fmt.Sprint() and urlencoded.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithQuery("a", 123) req.WithQuery("b", "foo") // URL is now http://example.com/path?a=123&b=foo
func (*Request) WithQueryString ¶
WithQueryString parses given query string and adds it to Request URL.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithQuery("a", 11) req.WithQueryString("b=22&c=33") // URL is now http://example.com/path?a=11&bb=22&c=33
func (*Request) WithText ¶
WithText sets Content-Type header to "text/plain; charset=utf-8" and sets body to given string.
Example:
req := NewRequest(config, "PUT", "http://example.com/path") req.WithText("hello, world!")
func (*Request) WithURL ¶
WithURL sets Request URL.
This URL overwrites Config.BaseURL. Request path passed to NewRequest() is appended to this URL, separated by slash if necessary.
Example:
req := NewRequest(config, "PUT", "/path") req.WithURL("http://example.com") // URL is now http://example.com/path
type RequestFactory ¶
type RequestFactory interface {
NewRequest(method, urlStr string, body io.Reader) (*http.Request, error)
}
RequestFactory is used to create all http.Request objects.
func DefaultRequestFactory ¶
func DefaultRequestFactory() RequestFactory
DefaultRequestFactory return a defaultRequestFactory Instance.