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)
- 10% discount on LightPaper markdown editor app for Silk users: use
SILKTEST
code.
(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