https://github.com/caicloud/aloe
Declarative API test framework based on ginkgo and gomega
https://github.com/caicloud/aloe
api engineering test
Last synced: about 1 year ago
JSON representation
Declarative API test framework based on ginkgo and gomega
- Host: GitHub
- URL: https://github.com/caicloud/aloe
- Owner: caicloud
- License: apache-2.0
- Created: 2017-12-26T11:56:00.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2019-09-10T07:54:51.000Z (almost 7 years ago)
- Last Synced: 2025-03-29T11:34:40.719Z (over 1 year ago)
- Topics: api, engineering, test
- Language: Go
- Homepage:
- Size: 2.67 MB
- Stars: 20
- Watchers: 13
- Forks: 14
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Aloe
[](https://travis-ci.org/caicloud/aloe)
[](https://coveralls.io/github/caicloud/aloe?branch=master)
[](http://godoc.org/github.com/caicloud/aloe)
[](https://goreportcard.com/report/github.com/caicloud/aloe)
Aloe is a declarative API test framework based on
[ginkgo](https://github.com/onsi/ginkgo),
[gomega](https://github.com/onsi/gomega)
and [yaml](http://yaml.org/). It aims to help write and read API test cases
simpler.
DISCLAIMER:
- only json API is supported now
- avoid using Aloe for extremely complex test, use ginkgo directly instead
## Terminology
There are two important concepts in aloe:
- `case`: case means a test case, for example, get an endpoint and verify its
output.
- `context`: to simply put, a context is a group of cases. Usually, context is
used to init data in database, so that all test cases will be tested in a
determined context.
## Getting Started
Following is a getting started example for using Aloe. First, create a
directory to put `context` and `case` yaml files.
```
mkdir -p test/testdata
```
Then, define your `context` in `context.yaml`.
```yaml
# test/testdata/context.yaml
summary: "CRUD Test example"
flow:
- description: "Init a product"
request:
api: POST /products
headers:
"Content-Type": "application/json"
body: |
{
"id": "1",
"title": "test"
}
response:
statusCode: 201
definitions:
- name: "testProductId"
selector:
- "id"
```
As mentioned above, a context is used to run a group of test cases in a
determined environment. In the above example,
we define a context which simply sends a POST request to `/products` with
product name `test`; therefore, all test
cases in this context will expect product `test` exists.
Now with context setup, we can start defining `case`. Here, we define a test
case in `test/testdata/get.yaml` to get
and verify product `test`.
```yaml
# test/testdata/get.yaml
description: "Try to GET a product"
flow:
- description: "Get the product with title test"
request:
api: GET /products/%{testProductId}
headers:
"Content-Type": "application/json"
response:
statusCode: 200
```
Finally, some go codes should be written in `test` directory to run the test
case:
```go
func init() {
aloe.Init(nil)
}
func RunTEST(t *testing.T) {
aloe.AppendDataDirs("testdata")
if err := aloe.Env("host", "localhost:8080"); err != nil {
fmt.Printf("can't set env host: %v", err)
os.Exit(1)
}
if err := aloe.RegisterCleaner(s); err != nil {
fmt.Printf("can't register cleaner: %v", err)
os.Exit(1)
}
aloe.Run(t)
}
var _ = ginkgo.BeforeSuite(func() {
s.Register()
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("can't begin server")
os.Exit(1)
}
go http.Serve(listener, nil)
})
```
## Usage
### Variable
Variables can be defined to hold auto-generated value by server (e.g. id). For
example:
```yaml
flow:
- description: "Init a product"
definitions:
- name: "testProductId"
selector:
- "id"
```
A variable called `testProductId` will be defined. The value of `testProductId`
is from the round trip response.
Variable can also be a json snippet.
```
response:
{
"id": "111",
"title": "test",
"comments":[
"aaa",
"bbb"
]
}
// id will select value of string
["id"] => 111(without quote)
// empty selector will select whole body
[] => {
"id": "111",
"title": "test",
"comments":[
"aaa",
"bbb"
]
}
// comments will select partial body
["comments"] => [
"aaa",
"bbb"
]
// comments.0 will select first element of array
["comments", "0"] => aaa
```
If a variables is defined, it can be used in round trip with format `%{name}`.
### Body validator
Body validator is used to validate response fields. Some special validators are
predefined, e.g. `$regexp`
```yaml
flow:
- description: "Create a product"
response:
# validate that id format matches regexp
# validate that password field is not returned
body: |
{
"id": {
"$regexp": "[a-zA-Z][a-zA-Z0-9-]{11}"
},
"password": {
"$exists": false,
},
}
```
Now only `$regexp` and `$exists` is supported (more special validator will be
added in the future).
### Cleaner
Cleaner can be used to clean context after all cases in the context are
finished.
```go
type Cleaner interface {
// Name defines cleaner name
Name() string
// Clean will be called after all of the cases in the context are
// finished
Clean(variables map[string]jsonutil.Variable) error
}
```
Users can implement their own cleaners and call RegisterCleaner in framework.
Then cleaners can be used in context file.
```yaml
# test/testdata/get.yaml
summary: "Create a product"
flow:
- description: "Create a product"
request:
api: POST /products
response:
statusCode: 201
cleaner: "productCleaner"
```
### Presetter
Presetter can be used to preset all RoundTrips in the context.
```go
// Presetter defines presetter
type Presetter interface {
// Name defines name of presetter
Name() string
// Preset parse args and set roundtrip template
Preset(rt *types.RoundTrip, args map[string]string) (*types.RoundTrip,
error)
}
```
Users can implement their own presetters and call RegisterPresetter in
framework.
Then presetters can be used in context file.
```yaml
# test/testdata/get.yaml
summary: "Create a product"
presetter:
- name: "header"
args:
content-type: application/json
flow:
- description: "Create a product"
request:
api: POST /products
response:
statusCode: 201
```
### Nested context
Context can be nested just like directory. Child context will see all setup in
parent context.
```
tests
└── testdata
├── _context.yaml
├── basic
│ ├── _context.yaml
│ ├── create.yaml
│ └── update.yaml
├── failure
│ ├── _context.yaml
│ └── create.yaml
└── list
├── _context.yaml
└── list_all.yaml
```
## Examples
For more examples, see:
- [crud](./examples/crud)