cute
cute copied to clipboard
Library for simply creating HTTP tests in Go with Allure reports.
CUTE — create your tests easily
HTTP and REST API testing for Go.
Three steps for testing your HTTP service:
- Create request and write assets
- Run tests
- Check allure
Head of contents:
- Head of contents
- Installation
- Features
- Demo
-
Examples
- Single test with Allure
- Suite tests
-
Asserts
- JSON asserts
- Headers asserts
- JSON schema
-
Custom asserts
- Base
- T
- Errors
- Global Environment Keys
Installation
go get -u github.com/ozontech/cute
Requirements
- Go 1.17+
Features
- Full integration with Allure
- Expressive and intuitive syntax
- Built-in JSON support
- Custom asserts
- One step to BDD
Demo
- Install allure
$ brew install allure
- Run example
$ make example
- Run allure
$ allure serve ./examples/allure-results
Examples
See examples directory for featured examples.
Single test
See an example of creating a single test.
For a result with allure information you can use testing.T
or provider.T
from allure-go.
import (
"context"
"net/http"
"path"
"testing"
"time"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/json"
)
func TestExample(t *testing.T) {
cute.NewTestBuilder().
Title("Title").
Description("some_description").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusOK).
AssertBody(
json.Equal("$[0].email", "[email protected]"),
json.Present("$[1].name"),
).
ExecuteTest(context.Background(), t)
}
See full example here
Allure:
Suite
Suite provides a structure in which you can describe tests by grouping them into test suites. This can be useful if you have a lot of different tests and it is difficult to navigate through them without having additional "layers nesting levels" of test calls.
You can read about Allure.Suite
here
- Declare a structure with
suite.Suite
and*cute.HTTPTestMaker
import (
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
)
type ExampleSuite struct {
suite.Suite
host *url.URL
testMaker *cute.HTTPTestMaker
}
func (i *ExampleSuite) BeforeAll(t provider.T) {
// Prepare http test builder
i.testMaker = cute.NewHTTPTestMakerSuite()
// Preparing host
host, err := url.Parse("https://jsonplaceholder.typicode.com/")
if err != nil {
t.Fatalf("could not parse url, error %v", err)
}
i.host = host
}
- Declare test
import (
"github.com/ozontech/allure-go/pkg/framework/suite"
)
func TestExampleTest(t *testing.T) {
suite.RunSuite(t, new(ExampleSuite))
}
- Just relax and describe tests
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/headers"
"github.com/ozontech/cute/asserts/json"
)
func (i *ExampleSuite) TestExample_OneStep(t provider.T) {
var (
testBuilder = i.testMaker.NewTestBuilder()
)
u, _ := url.Parse(i.host.String())
u.Path = path.Join(u.Path, "/posts/1/comments")
testBuilder.
Title("TestExample_OneStep").
Tags("one_step", "some_local_tag", "json").
Create().
StepName("Example GET json request").
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
"some_array_header": []string{"1", "2", "3", "some_thing"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectJSONSchemaFile("file://./resources/example_valid_request.json").
ExpectStatus(http.StatusOK).
AssertBody(
json.Equal("$[0].email", "[email protected]"),
json.Present("$[1].name"),
json.NotPresent("$[1].some_not_present"),
json.GreaterThan("$", 3),
json.Length("$", 5),
json.LessThan("$", 100),
json.NotEqual("$[3].name", "kekekekeke"),
).
OptionalAssertBody(
json.GreaterThan("$", 3),
json.Length("$", 5),
json.LessThan("$", 100),
).
AssertHeaders(
headers.Present("Content-Type"),
).
ExecuteTest(context.Background(), t)
}
See full example here
Allure:
Asserts
You can create your own asserts or use ready-made asserts from the package asserts
JSON asserts:
You can find implementation here
-
Equal
is a function to assert that a jsonpath expression matches the given value -
NotEqual
is a function to check that jsonpath expression value is not equal to the given value -
Length
is a function to assert that value is the expected length -
GreaterThan
is a function to assert that value is greater than the given length -
LessThan
is a function to assert that value is less than the given length -
Present
is a function to assert that value is present (value can be 0 or null) -
NotEmpty
is a function to assert that value is present and not empty (value can't be 0 or null) -
NotPresent
is a function to assert that value is not present
Headers asserts:
See implementation here
-
Present
is a function to assert that header is present -
NotPresent
is a function to assert that header is not present
JSON schema validations:
There are three ways to validate a JSON Schema. It all depends on where you have it.
-
ExpectJSONSchemaString(string)
- is a function for compares a JSON schema from a string. -
ExpectJSONSchemaByte([]byte)
- is a function for compares a JSON schema from an array of bytes. -
ExpectJSONSchemaFile(string)
- is a function for compares a JSON schema from a file or remote resource.
Allure:
Custom asserts
You can implement 3 type of asserts:
Base
Types for creating custom assertions.
type AssertBody func(body []byte) error
type AssertHeaders func(headers http.Header) error
type AssertResponse func(response *http.Response) error
Example:
func customAssertBody() asserts.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.New("response body is empty")
}
return nil
}
}
T
Types for creating custom assertions using Allure Actions and testing.TB.
You can log some information to Allure.
Also you can log error on Allure yourself or just return error.
type AssertBodyT func(t cute.T, body []byte) error
type AssertHeadersT func(t cute.T, headers http.Header) error
type AssertResponseT func(t cute.T, response *http.Response) error
Example with T:
func customAssertBodyT() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
require.GreaterOrEqual(t, len(bytes), 100)
return nil
}
}
Example with step creations:
func customAssertBodySuite() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
step := allure.NewSimpleStep("Custom assert step")
defer func() {
t.Step(step)
}()
if len(bytes) == 0 {
step.Status = allure.Failed
step.Attachment(allure.NewAttachment("Error", allure.Text, []byte("response body is empty")))
return nil
}
return nil
}
}
Allure:
Assert errors
You can use method errors.NewAssertError
from package errors:
Example:
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/errors"
)
func customAssertBodyWithCustomError() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.NewAssertError("customAssertBodyWithCustomError", "body must be not empty", "len is 0", "len more 0")
}
return nil
}
}
If you'd like to create a pretty error in your custom assert you should implement error with interfaces:
With name
type WithNameError interface {
GetName() string
SetName(string)
}
With parameters for allure step
type WithFields interface {
GetFields() map[string]interface{}
PutFields(map[string]interface{})
}
Allure:
Optional assert
If assert returns optional error step will be failed but test will be success.
You can use method errors.NewOptionalError(error)
from package errors:
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/errors"
)
func customAssertBodyWithCustomError() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.NewOptionalError("body is empty")
}
return nil
}
}
To create optional error you should implement error with interface
type OptionalError interface {
IsOptional() bool
SetOptional(bool)
}
Allure:
Global Environment Keys
Key | Meaning | Default |
---|---|---|
ALLURE_OUTPUT_PATH |
Path to output allure results | . (Folder with tests) |
ALLURE_OUTPUT_FOLDER |
Name result folder | /allure-results |
ALLURE_ISSUE_PATTERN |
Url pattepn to issue. Must contain %s |
|
ALLURE_TESTCASE_PATTERN |
URL pattern to TestCase. Must contain %s . |
|
ALLURE_LAUNCH_TAGS |
Default tags for all tests. Tags must be separated by commas. |