Markdown based document-driven web API testing.
- Write nice looking Markdown documentation (like this), and then run it using the silk command
- Simple and robust Markdown API
- Comes with real examples that you can copy (that are also part of the test suite for the project)
(VIDEO) Watch the talk about Silk (with slides) or read about Silk in this blog post.
Tests are made up of documents written in Markdown.
# Group
- Top level headings represent groups of requests## GET /path
- Second level headings represent a request- Code blocks with three back tics represent bodies
* Field: value
- Lists describe headers and assertions* ?param=value
- Request parameters===
seperators break requests from responses- Comments (starting with
//
) are ignored - Plain text is ignored to allow you to add documentation
- Inline back tics are ignored and are available for formatting
A document is made up of:
- A request
===
seperator- Assertions
A request starts with ##
and must have an HTTP method, and a path:
## METHOD /path
Examples include:
## GET /people
## POST /people/1/comments
## DELETE /people/1/comments/2
To specify a request body (for example for POST
requests) use a codeblock using backtics (```
):
```
{"name": "Silk", "release_year": 2016}
```
You may specify request headers using lists (prefixed with *
):
* Content-Type: "application/json"
* X-Custom-Header: "123"
Adding parameters to the path (like GET /path?q=something
) can be tricky, especially when you consider escaping etc. To address this, Silk supports parameters like lists:
* ?param=value
The parameters will be correctly added to the URL path before the request is made.
Setting cookies on a request can be done using the HTTP header pattern:
* Cookie: "key=value"
- See asserting cookies.
Following the ===
separator, you can specify assertions about the response. At a minimum, it is recommended that you assert the status code to ensure the request succeeded:
* Status: 200
You may also specify response headers in the same format as request headers:
* Content-Type: "application/json"
* X-MyServer-Version: "v1.0"
If any of the headers do not match, the test will fail.
To assert that a cookie is present in a response, make a regex assertion against the Set-Cookie
HTTP header:
* Set-Cookie: /key=value/
- All cookie strings are present in a single
Set-Cookie
seperated by a pipe character.
You can optionally include a verbatim body using code blocks surrounded by three back tics. If the response body does not exactly match, the test will fail:
```
{"id": 1, "name": "Silk", "release_year": 2016}
```
You may also make any number of regex assertions against the body using the Body
object:
* Body: /Hello world/
* Body: /This should be found too/
* Body: /and this/
Alternatively, you can specify a list (using *
) of data fields to assert accessible via the Data
object:
* Status: 201
* Content-Type: "application/json"
* Data.name: "Silk"
* Data.release_year: 2016
* Data.tags[0]: "testing"
* Data.tags[1]: "markdown"
* Data[0].name: "Mat"
* Data[1].name: "David"
- NOTE: Currenly this feature is only supported for JSON APIs.
Values may be regex, if they begin and end with a forward slash: /
. The assertion will pass if the value (after being turned into a string) matches the regex.
* Status: /^2.{2}$/
* Content-Type: /application/json/
The above will assert that:
- The status looks like
2xx
, and - The
Content-Type
containsapplication/json
The silk
command runs tests against an HTTP endpoint.
Usage:
silk -silk.url="{endpoint}" {testfiles}
{url}
the endpoint URL (e.g.http://localhost:8080
){testfiles}
path to test files (e.g../testfiles
)
Notes:
- Omit trailing slash from
url
{testfiles}
can include a pattern (e.g./path/*.silk.md
)
Silk is written in Go and integrates seamlessly into existing testing tools and frameworks. Import the runner
package and use RunGlob
to match many test files:
package project_test
import (
"testing"
"github.com/matryer/silk/runner"
)
func TestAPIEndpoint(t *testing.T) {
// start a server
s := httptest.NewServer(yourHandler)
defer s.Close()
// run all test files
runner.New(t, s.URL).RunGlob(filepath.Glob("../testfiles/failure/*.silk.md"))
}
- Special thanks to @dahernan for his contributions and criticisms of Silk
- Silk logo by Chris Ryer