README
¶
forest - for testing REST api-s in Go
This package provides a few simple helper types and functions to create functional tests that call a running REST based WebService.
install
go get github.com/emicklei/forest
simple example
package main
import (
"net/http"
"testing"
. "github.com/emicklei/forest"
)
var github = NewClient("https://api.github.com", new(http.Client))
func TestForestProjectExists(t *testing.T) {
cfg := NewConfig("/repos/emicklei/{repo}", "forest").Header("Accept", "application/json")
r := github.GET(t, cfg)
ExpectStatus(t, r, 200)
}
graphql support
query := forest.NewGraphQLRequest(list_matrices_query, "ListMatrices")
query, err = query.WithVariablesFromString(`
{ "repositoryID":"99426e24-..........-6bf9770f1fd5", "page":{ "first":20 }, }`) // ... handle error cfg := forest.NewRequestConfig(...) cfg.Content(query, "application/json") r := SkillsAPI.POST(t, cfg) ExpectStatus(t, r, 200)
other helper functions
func ExpectHeader(t T, r *http.Response, name, value string)
func ExpectJSONArray(t T, r *http.Response, callback func(array []interface{}))
func ExpectJSONDocument(t T, r *http.Response, doc interface{})
func ExpectJSONHash(t T, r *http.Response, callback func(hash map[string]interface{}))
func ExpectStatus(t T, r *http.Response, status int) bool
func ExpectString(t T, r *http.Response, callback func(content string))
func ExpectXMLDocument(t T, r *http.Response, doc interface{})
func JSONArrayPath(t T, r *http.Response, dottedPath string) interface{}
func JSONPath(t T, r *http.Response, dottedPath string) interface{}
func ProcessTemplate(t T, templateContent string, value interface{}) string
func Scolorf(syntaxCode string, format string, args ...interface{}) string
func SkipUnless(s skippeable, labels ...string)
func XMLPath(t T, r *http.Response, xpath string) interface{}
func Dump(t T, resp *http.Response)
more docs
© 2016+, http://ernestmicklei.com. MIT License. Contributions welcome.
Documentation
¶
Overview ¶
Package forest has functions for REST Api testing in Go
This package provides a few simple helper types and functions to create functional tests that call HTTP services. A test uses a forest Client which encapsulates a standard http.Client and a base url. Such a client can be created inside a function or by initializing a package variable for shared access. Using a client, you can send http requests and call multiple expectation functions on each response.
Most functions of the forest package take the *testing.T variable as an argument to report any error.
Example
// setup a shared client to your API var chatter = forest.NewClient("http://api.chatter.com", new(http.Client)) func TestGetMessages(t *testing.T) { r := chatter.GET(t, forest.Path("/v1/messages").Query("user","zeus")) ExpectStatus(t,r,200) ExpectJSONArray(t,r,func(messages []interface{}){ // in the callback you can validate the response structure if len(messages) == 0 { t.Error("expected messages, got none") } }) }
To compose http requests, you create a RequestConfig value which as a Builder interface for setting the path,query,header and body parameters. The ProcessTemplate function can be useful to create textual payloads. To inspect http responses, you use the Expect functions that perform the unmarshalling or use XMLPath or JSONPath functions directly on the response.
If needed, implement the standard TestMain to do global setup and teardown.
func TestMain(m *testing.M) { // there is no *testing.T available, use an stdout implementation t := forest.TestingT // setup chatter.PUT(t, forest.Path("/v1/messages/{id}",1).Body("<payload>")) ExpectStatus(t,r,204) exitCode := m.Run() // teardown chatter.DELETE(t, forest.Path("/v1/messages/{id}",1)) ExpectStatus(t,r,204) os.Exit(exitCode) }
Special features ¶
In contrast to the standard behavior, the Body of a http.Response is made re-readable. This means one can apply expectations to a response as well as dump the full contents.
The function XMLPath provides XPath expression support. It uses the [https://godoc.org/launchpad.net/xmlpath] package. The similar function JSONPath can be used on JSON documents.
Colorizes error output (can be configured using package vars).
All functions can also be used in a setup and teardown as part of TestMain.
(c) 2015, http://ernestmicklei.com. MIT License
Index ¶
- Variables
- func CheckError(t T, err error) bool
- func CookieNamed(resp *http.Response, name string) *http.Cookie
- func Dump(t T, resp *http.Response)
- func Errorf(t *testing.T, format string, args ...interface{})
- func ExpectHeader(t T, r *http.Response, name, value string) bool
- func ExpectJSONArray(t T, r *http.Response, callback func(array []interface{})) bool
- func ExpectJSONDocument(t T, r *http.Response, doc interface{}) bool
- func ExpectJSONHash(t T, r *http.Response, callback func(hash map[string]interface{})) bool
- func ExpectStatus(t T, r *http.Response, status int) bool
- func ExpectString(t T, r *http.Response, callback func(content string)) bool
- func ExpectXMLDocument(t T, r *http.Response, doc interface{}) bool
- func Fatalf(t *testing.T, format string, args ...interface{})
- func IsMaskedHeader(name string) bool
- func JSONArrayPath(t T, r *http.Response, dottedPath string) interface{}
- func JSONPath(t T, r *http.Response, dottedPath string) interface{}
- func Logf(t T, format string, args ...interface{})
- func MaskHeader(name string)
- func ProcessTemplate(t T, templateContent string, value interface{}) string
- func Scolorf(syntaxCode string, format string, args ...interface{}) string
- func SkipUnless(t skippeable, labels ...string)
- func URLPathEncode(path string) string
- func VerboseOnFailure(verbose bool)
- func XMLPath(t T, r *http.Response, xpath string) interface{}
- type APITesting
- func (a *APITesting) DELETE(t T, config *RequestConfig) *http.Response
- func (a *APITesting) Do(method string, config *RequestConfig) (*http.Response, error)
- func (a *APITesting) GET(t T, config *RequestConfig) *http.Response
- func (a *APITesting) PATCH(t T, config *RequestConfig) *http.Response
- func (a *APITesting) POST(t T, config *RequestConfig) *http.Response
- func (a *APITesting) PUT(t T, config *RequestConfig) *http.Response
- type GraphQLRequest
- type JUnitProperty
- type JUnitReport
- type JUnitTestCase
- type JUnitTestCaseFailure
- type JUnitTestCaseSkipped
- type JUnitTestSuite
- type Logger
- type Map
- type RequestConfig
- func (r *RequestConfig) BasicAuth(username, password string) *RequestConfig
- func (r *RequestConfig) Body(body string) *RequestConfig
- func (r *RequestConfig) Build(method, baseURL string) (*http.Request, error)
- func (r *RequestConfig) Content(payload interface{}, contentType string) *RequestConfig
- func (r *RequestConfig) Cookie(c *http.Cookie) *RequestConfig
- func (r *RequestConfig) Do(block func(config *RequestConfig)) *RequestConfig
- func (r *RequestConfig) Form(bodyData url.Values) *RequestConfig
- func (r *RequestConfig) Header(name, value string) *RequestConfig
- func (r *RequestConfig) LogRequestLine(b bool)
- func (r *RequestConfig) Path(pathTemplate string, pathParams ...interface{}) *RequestConfig
- func (r *RequestConfig) Query(name string, value interface{}) *RequestConfig
- func (r *RequestConfig) Read(bodyReader io.Reader) *RequestConfig
- type T
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrorColorSyntaxCode = "@{wR}"
ErrorColorSyntaxCode requires the syntax defined on https://github.com/wsxiaoys/terminal/blob/master/color/color.go . Set to an empty string to disable coloring.
var FatalColorSyntaxCode = "@{wR}"
FatalColorSyntaxCode requires the syntax defined on https://github.com/wsxiaoys/terminal/blob/master/color/color.go . Set to an empty string to disable coloring.
var LoggingPrintf = fmt.Printf
LoggingPrintf is the function used by TestingT to produce logging on Logf,Error and Fatal.
var MaskChar = "*"
MaskChar is used the create a masked header value.
var NewRequestConfig = NewConfig
NewRequestConfig is an alias for NewConfig
var Path = NewConfig
Path is an alias for NewConfig
var TerminalColorsEnabled = true
TerminalColorsEnabled can be changed to disable the use of terminal coloring. One usecase is to add a command line flag to your test that controls its value.
func init() { flag.BoolVar(&forest.TerminalColorsEnabled, "color", true, "want colors?") } go test -color=false
var TestingT = Logger{InfoEnabled: true, ErrorEnabled: true, ExitOnFatal: true}
TestingT provides a sub-api of testing.T. Its purpose is to allow the use of this package in TestMain(m).
Functions ¶
func CheckError ¶
CheckError simply tests the error and fail is not undefined. This is implicity called after sending a Http request. Return true if there was an error.
func CookieNamed ¶ added in v1.3.0
CookieNamed returns the cookie with matching name. Returns nil if not found.
func ExpectHeader ¶
ExpectHeader inspects the header of the response. Return true if the header matches.
Example ¶
Output:
func ExpectJSONArray ¶
ExpectJSONArray tries to unmarshal the response body into a Go slice callback parameter. Fail if the body could not be read or if unmarshalling was not possible. Returns true if the callback was executed with an array.
Example ¶
Output:
func ExpectJSONDocument ¶
ExpectJSONDocument tries to unmarshal the response body into fields of the provided document (struct). Fail if the body could not be read or unmarshalled. Returns true if a document could be unmarshalled.
func ExpectJSONHash ¶
ExpectJSONHash tries to unmarshal the response body into a Go map callback parameter. Fail if the body could not be read or if unmarshalling was not possible. Returns true if the callback was executed with a map.
Example ¶
Output:
func ExpectStatus ¶
ExpectStatus inspects the response status code. If the value is not expected, the complete request, response is logged (iff verboseOnFailure) and the test is aborted. Return true if the status is as expected.
Example ¶
Output:
func ExpectString ¶
ExpectString reads the response body into a Go string callback parameter. Fail if the body could not be read or unmarshalled. Returns true if a response body was read.
func ExpectXMLDocument ¶
ExpectXMLDocument tries to unmarshal the response body into fields of the provided document (struct). Fail if the body could not be read or unmarshalled. Returns true if a document could be unmarshalled.
Example ¶
How to use the ExpectXMLDocument function on a http response.
Output:
func IsMaskedHeader ¶ added in v1.1.0
IsMaskedHeader return true if the name is part of (case-insensitive match) the MaskHeaderNames.
func JSONArrayPath ¶
JSONArrayPath returns the value found by following the dotted path in a JSON array. E.g .1.title in [ {"title":"Go a long way"}, {"title":"scary scala"} ]
Example ¶
Output:
func JSONPath ¶
JSONPath returns the value found by following the dotted path in a JSON document hash. E.g .chapters.0.title in { "chapters" : [{"title":"Go a long way"}] }
Example ¶
Output:
func MaskHeader ¶ added in v1.1.0
func MaskHeader(name string)
MaskHeader is used to prevent logging secrets.
func ProcessTemplate ¶
ProcessTemplate creates a new text Template and executes it using the provided value. Returns the string result of applying this template. Failures in the template are reported using t.
func Scolorf ¶
Scolorf returns a string colorized for terminal output using the syntaxCode (unless that's empty). Requires the syntax defined on https://github.com/wsxiaoys/terminal/blob/master/color/color.go .
func SkipUnless ¶
func SkipUnless(t skippeable, labels ...string)
SkipUnless will Skip the test unless the LABELS environment variable includes any of the provided labels.
LABELS=integration,nightly go test -v
Example ¶
Output:
func URLPathEncode ¶
func VerboseOnFailure ¶
func VerboseOnFailure(verbose bool)
VerboseOnFailure (default is false) will produce more information about the request and response when a failure is detected on an expectation. This setting is not the same but related to the value of testing.Verbose().
Types ¶
type APITesting ¶
type APITesting struct { BaseURL string // contains filtered or unexported fields }
APITesting provides functions to call a REST api and validate its responses.
func NewClient ¶
func NewClient(baseURL string, httpClient *http.Client) *APITesting
NewClient returns a new ApiTesting that can be used to send Http requests.
func (*APITesting) DELETE ¶
func (a *APITesting) DELETE(t T, config *RequestConfig) *http.Response
DELETE sends a Http request using a config (headers,...) The request is logged and any sending error will fail the test.
func (*APITesting) Do ¶
func (a *APITesting) Do(method string, config *RequestConfig) (*http.Response, error)
Do sends a Http request using a Http method (GET,PUT,POST,....) and config (headers,...) The request is not logged and any URL build error or send error will be returned.
func (*APITesting) GET ¶
func (a *APITesting) GET(t T, config *RequestConfig) *http.Response
GET sends a Http request using a config (headers,...) The request is logged and any sending error will fail the test.
func (*APITesting) PATCH ¶
func (a *APITesting) PATCH(t T, config *RequestConfig) *http.Response
PATCH sends a Http request using a config (headers,...) The request is logged and any sending error will fail the test.
func (*APITesting) POST ¶
func (a *APITesting) POST(t T, config *RequestConfig) *http.Response
POST sends a Http request using a config (headers,body,...) The request is logged and any sending error will fail the test.
func (*APITesting) PUT ¶
func (a *APITesting) PUT(t T, config *RequestConfig) *http.Response
PUT sends a Http request using a config (headers,body,...) The request is logged and any sending error will fail the test.
type GraphQLRequest ¶ added in v1.2.0
type GraphQLRequest struct { Query string `json:"query,omitempty"` OperationName string `json:"operationName"` Variables map[string]interface{} `json:"variables"` }
GraphQLRequest is used to model both a query or a mutation request
func NewGraphQLRequest ¶ added in v1.2.0
func NewGraphQLRequest(query, operation string, vars ...Map) GraphQLRequest
NewGraphQLRequest returns a new Request (for query or mutation) without any variables.
func (GraphQLRequest) Reader ¶ added in v1.2.0
func (r GraphQLRequest) Reader() io.Reader
Reader returns a new reader for sending it using a HTTP request.
func (GraphQLRequest) WithVariablesFromString ¶ added in v1.2.0
func (r GraphQLRequest) WithVariablesFromString(jsonhash string) (GraphQLRequest, error)
WithVariablesFromString returns a copy of the request with decoded variables. Returns an error if the jsonhash cannot be converted.
type JUnitProperty ¶ added in v1.7.0
type JUnitReport ¶ added in v1.7.0
type JUnitReport struct {
TestSuites []JUnitTestSuite `xml:"testsuite"`
}
func ReadJUnitReport ¶ added in v1.7.0
func ReadJUnitReport(filename string) (r JUnitReport, err error)
type JUnitTestCase ¶ added in v1.7.0
type JUnitTestCase struct { Classname string `xml:"classname,attr"` Name string `xml:"name,attr"` Time float64 `xml:"time,attr"` Failure *JUnitTestCaseFailure `xml:"failure"` Skipped *JUnitTestCaseSkipped `xml:"skipped"` }
type JUnitTestCaseFailure ¶ added in v1.7.0
type JUnitTestCaseSkipped ¶ added in v1.7.0
type JUnitTestCaseSkipped struct {
Message string `xml:"message,attr"`
}
type JUnitTestSuite ¶ added in v1.7.0
type JUnitTestSuite struct { Tests int `xml:"tests,attr"` Failures int `xml:"failures,attr"` Time float64 `xml:"time,attr"` Name string `xml:"name,attr"` Timestamp time.Time `xml:"timestamp,attr"` Properties []JUnitProperty `xml:"properties"` TestCases []JUnitTestCase `xml:"testcase"` }
type Logger ¶
Logger can be used for the testing.T parameter for forest functions when you need more control over what to log and how to handle fatals. The variable TestingT is a Logger with all enabled.
func (Logger) Error ¶
func (l Logger) Error(args ...interface{})
Error is equivalent to Log followed by Fail.
func (Logger) Fail ¶
func (l Logger) Fail()
Fail marks the function as having failed but continues execution.
func (Logger) FailNow ¶
func (l Logger) FailNow()
FailNow marks the function as having failed and stops its execution.
type RequestConfig ¶
type RequestConfig struct { URI string BodyReader io.Reader HeaderMap http.Header // for Query parameters Values url.Values FormData url.Values User, Password string Cookies []*http.Cookie // contains filtered or unexported fields }
RequestConfig holds additional information to construct a Http request.
Example ¶
Output:
func NewConfig ¶
func NewConfig(pathTemplate string, pathParams ...interface{}) *RequestConfig
NewConfig returns a new RequestConfig with initialized empty headers and query parameters. See Path for an explanation of the function parameters.
func (*RequestConfig) BasicAuth ¶
func (r *RequestConfig) BasicAuth(username, password string) *RequestConfig
BasicAuth sets the credentials for Basic Authentication (if username is not empty)
func (*RequestConfig) Body ¶
func (r *RequestConfig) Body(body string) *RequestConfig
Body sets the playload as is. No content type is set. It sets the BodyReader field of the RequestConfig.
func (*RequestConfig) Build ¶ added in v1.5.3
func (r *RequestConfig) Build(method, baseURL string) (*http.Request, error)
Build returns a new HTTP Request.
func (*RequestConfig) Content ¶
func (r *RequestConfig) Content(payload interface{}, contentType string) *RequestConfig
Content encodes (marshals) the payload conform the content type given. If the payload is already a string (JSON,XML,plain) then it is used as is. Supported Content-Type values for marshalling: application/json, application/xml, text/plain Payload can also be a slice of bytes; use application/octet-stream in that case. It sets the BodyReader field of the RequestConfig.
func (*RequestConfig) Cookie ¶ added in v1.3.0
func (r *RequestConfig) Cookie(c *http.Cookie) *RequestConfig
Cookie adds a Cookie to the list of cookies to include in the request.
func (*RequestConfig) Do ¶
func (r *RequestConfig) Do(block func(config *RequestConfig)) *RequestConfig
Do calls the one-argument function parameter with the receiver. This allows for custom convenience functions without breaking the fluent programming style.
func (*RequestConfig) Form ¶
func (r *RequestConfig) Form(bodyData url.Values) *RequestConfig
Form set the FormData values e.g for POST operation.
func (*RequestConfig) Header ¶
func (r *RequestConfig) Header(name, value string) *RequestConfig
Header adds a name=value pair to the list of header parameters.
func (*RequestConfig) LogRequestLine ¶ added in v1.4.3
func (r *RequestConfig) LogRequestLine(b bool)
LogRequestLine controls whether each HTTP verb call is logging the request line (method + url)
func (*RequestConfig) Path ¶
func (r *RequestConfig) Path(pathTemplate string, pathParams ...interface{}) *RequestConfig
Path sets the URL path with optional path parameters. format example: /v1/persons/{param}/ + 42 => /v1/persons/42 format example: /v1/persons/:param/ + 42 => /v1/persons/42 format example: /v1/assets/*rest + js/some/file.js => /v1/assets/js/some/file.js
func (*RequestConfig) Query ¶
func (r *RequestConfig) Query(name string, value interface{}) *RequestConfig
Query adds a name=value pair to the list of query parameters.
func (*RequestConfig) Read ¶
func (r *RequestConfig) Read(bodyReader io.Reader) *RequestConfig
Read sets the BodyReader for content to send with the request.
type T ¶
type T interface { // Logf formats its arguments according to the format, analogous to Printf, and records the text in the error log. // The text will be printed only if the test fails or the -test.v flag is set. Logf(format string, args ...interface{}) // Error is equivalent to Log followed by Fail. Error(args ...interface{}) // Fatal is equivalent to Log followed by FailNow. Fatal(args ...interface{}) // FailNow marks the function as having failed and stops its execution. FailNow() // Fail marks the function as having failed but continues execution. Fail() Helper() }
T is the interface that this package is using from standard testing.T