Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ozontech/allure-go
Complete Allure provider in Go which doesn't overload the interface usage
https://github.com/ozontech/allure-go
allure allure-framework go golang qa qaautomation qatools reporting reporting-tool testing
Last synced: 3 months ago
JSON representation
Complete Allure provider in Go which doesn't overload the interface usage
- Host: GitHub
- URL: https://github.com/ozontech/allure-go
- Owner: ozontech
- License: apache-2.0
- Created: 2022-01-11T12:47:45.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2024-10-24T16:56:54.000Z (3 months ago)
- Last Synced: 2024-10-25T21:39:36.497Z (3 months ago)
- Topics: allure, allure-framework, go, golang, qa, qaautomation, qatools, reporting, reporting-tool, testing
- Language: Go
- Homepage: https://t.me/allure_go_chat
- Size: 1.93 MB
- Stars: 312
- Watchers: 9
- Forks: 33
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-allure - allure-go - complete Allure provider in Go, without overloading the interface of usage. The project started as a fork of Testify, but over time it got its own runner and its own features. (Programming languages and frameworks / Go)
- awesome-golang-repositories - allure-go
README
# Allure-Go
![](.resources/allure_go_icon.svg)
Allure-Go - the project that provides a complete allure provider in go, without overloading the interface of usage.
The project started as a fork of testify, but over time it got its own runner and its own features.## :mortar_board: Head of contents
+ [:mortar_board: Head of contents](#mortar_board-head-of-contents)
+ [:zap: Features](#zap-features)
+ [WHAT'S NEW](#whats-new)
+ [pkg/allure](#sparkles-pkgallure)
+ [pkg/framework](#sparkles-pkgframework)
+ [:beginner: Getting Started with framework!](#beginner-getting-started-with-framework)
+ [No Suite tests](#no-suite-tests)
+ [Runner](#runner)
+ [Suite](#suite)
+ [:wrench: Configure your environment!](#wrench-configure-your-environment)
+ [:smirk: Going Deeper...](#smirk-going-deeper)
+ [pkg/allure](#pkgallure)
+ [pkg/framework](#pkgframework)
+ [cute](#cute)
+ [:school_satchel: Few more examples](#school_satchel-few-more-examples)
+ [:rocket: Async test](#async-test)
+ [Test with nested steps](#test-with-nested-steps)
+ [Test with attachments](#test-with-attachment)
+ [Run few parallel suites](#run-few-parallel-suites)
+ [Setup hooks](#setup-hooks)
+ [XSkip](#xskip)
+ [:rocket: Parametrized tests](#parametrized-test)
+ [Setup test](#setup-test)
+ [Prevent loosing allureID in test results](#Prevent-loosing-allureID-in-test-results)## :zap: Features
Providing a separate package allows you to customize your work with allure.
### What's new?
**Release v0.6.17**
#### WithTestSetup/WithTestTeardown methods
Now you can improve your reports with `t.WithTestSetup(func (provider.T))` or `t.WithTeardown(func (provider.T))`.
If you need some more setup customization, now you can pass your steps to `Set up` and `Tear down` right from the test!Check out [our example](./examples/suite_demo/setup_test.go) for more information, or check out example below:
:information_source: Feature works __only__ with Test. If you try to run it in Before/After hook or inside itself - nothing will happen.
:information_source: Yes, it works with t.Parallel, but HIGHLY recommended to run t.Parallel AFTER TestSetup.
:information_source: Yes, it works with TableTest.**Release v0.6.16**
#### :zap: Parametrized tests
New absolutely amazing way to build your table tests.
Have a look at [here](./examples/suite_demo/new_parametrized_test.go) or [here](#parametrizedtestexamplessuite_demonew_parametrized_testgo).:information_source: you need just create parameter field in suite struct and add argument to the test signature (pretty cool, hah?).
##### FAQ about table tests:
+ :question: Can I use this amazing feature with my common tests?
+ :information_source: **YES**, it works with any other type of suite's tests.+ :question:Can I use structs, pointers or interfaces as parameters?
+ :information_source: **YES** you can (and, I guess, you should) use it with structs and interfaces as params.+ :question: Can I use it with `TestRunner` object?
+ :information_source: **NO**, `TestRunner` object doesn't support this.#### SuiteResult
Now `suite.RunSuite` and `runner.RunTests` returns new adorable struct `SuiteResult` to customize your integrations.
:information_source: `SuiteResult` contains information about suite `Container` and each test's `Container` and `Result`.
### :sparkles: pkg/allure
The package containing the data model for Allure.
Complete list of allure objects:+ `Attachment`
+ `Container`
+ `Label`
+ `Link`
+ `Parameter`
+ `Result`
+ `Step`### :sparkles: pkg/framework
The package provides a fully integrated with Allure JUNIT-like framework for working with tests.
Main features::white_check_mark: **Allure support**
+ Test plan support (Allure TestOps feature)
+ Tests as code
+ Extensive configuration options for test steps
+ Testify's asserts already wrapped with `allure.Step`!
+ xSkip support (you can mark test as `t.XSkip()` and it will be skipped on fail):white_check_mark: **Suite support**
+ Before/After feature
+ Suite as go-struct
+ Suite as sub-test:white_check_mark: **Parallel running**
+ Parallel tests in suite structs
+ Parallel steps in test functions## :beginner: Getting Started with framework!
**Step 0.** Install package
```bash
go get github.com/ozontech/allure-go/pkg/framework
```### No Suite tests
**NOTE:** No suite tests doesn't support before after hooks
**Step 1.** Describe tests
```go
package testimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestRunner(t *testing.T) {
runner.Run(t, "My first test", func(t provider.T) {
t.NewStep("My First Step!")
})
runner.Run(t, "My second test", func(t provider.T) {
t.WithNewStep("My Second Step!", func(sCtx provider.StepCtx) {
sCtx.NewStep("My First SubStep!")
})
})
}
```**Step 2.** Run it!
```bash
go test ./test/...
```### Suite
**Step 1.** Make your first test suite
```go
package testsimport (
"github.com/ozontech/allure-go/pkg/framework/suite"
)type MyFirstSuite struct {
suite.Suite
}
```**Step 2.** Extend it with tests
```go
package testsimport (
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type MyFirstSuite struct {
suite.Suite
}func (s *MyFirstSuite) TestMyFirstTest(t provider.T) {
t.NewStep("My First Step!")
}func (s *MyFirstSuite) TestMySecondTest(t provider.T) {
t.WithNewStep("My Second Step!", func(sCtx provider.StepCtx) {
sCtx.NewStep("My First SubStep!")
})
}
```**Step 3.** Describe suite runner function
```go
package testimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type MyFirstSuite struct {
suite.Suite
}func (s *MyFirstSuite) TestMyFirstTest(t provider.T) {
t.NewStep("My First Step!")
}func (s *MyFirstSuite) TestMySecondTest(t provider.T) {
t.WithNewStep("My Second Step!", func(sCtx provider.StepCtx) {
sCtx.NewStep("My First SubStep!")
})
}func TestSuiteRunner(t *testing.T) {
suite.RunSuite(t, new(MyFirstSuite))
}
```**Step 4.** Run it!
```bash
go test ./test/...
```### Runner
**Step 1.** Init runner object
```go
package testimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestRunner(t *testing.T) {
r := runner.NewRunner(t, "My First Suite!")
}
```**Step 2.** Extend it with tests
```go
package testimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestRunner(t *testing.T) {
r := runner.NewRunner(t, "My First Suite!")
r.NewTest("My first test", func(t provider.T) {
t.NewStep("My First Step!")
})r.NewTest("My second test", func(t provider.T) {
t.WithNewStep("My Second Step!", func(sCtx provider.StepCtx) {
sCtx.NewStep("My First SubStep!")
})
})
}
```**Step 3.** Call RunTests function from runner
```go
package testimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestRunner(t *testing.T) {
r := runner.NewRunner(t, "My First Suite!")
r.NewTest("My first test", func(t provider.T) {
t.NewStep("My First Step!")
})r.NewTest("My second test", func(t provider.T) {
t.WithNewStep("My Second Step!", func(sCtx provider.StepCtx) {
sCtx.NewStep("My First SubStep!")
})
})
r.RunTests()
}
```**Step 4.** Run it!
```bash
go test ./test/...
```## :wrench: Configure your environment!
### Configure Behavior
The path to allure reports is gathered from the two global variables: `${ALLURE_OUTPUT_FOLDER}/${ALLURE_OUTPUT_PATH}`
:zap: The `ALLURE_OUTPUT_FOLDER` is the name of the folder where the allure reports will be stored (by
default, `allure-results`).---
:zap: The `ALLURE_OUTPUT_PATH` is the path where the `ALLURE_OUTPUT_FOLDER` will be created (by default this is the root
folder root folder of the test launcher).---
You can also specify several global configurations to integrate with your TMS or Task Tracker::zap: `ALLURE_ISSUE_PATTERN` - Specifies the url pattern for your Issues. Has no default value. **Mandatory**. Must
contain `%s`.If `ALLURE_ISSUE_PATTERN` is not specified, the link will be read in its entirety.
Example:
```go
package provider_demoimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestSampleDemo(t *testing.T) {
runner.Run(t, "Just Link", func(t provider.T) {
t.SetIssue("https://pkg.go.dev/github.com/stretchr/testify")
})runner.Run(t, "With Pattern", func(t provider.T) {
_ = os.Setenv("ALLURE_ISSUE_PATTERN", "https://pkg.go.dev/github.com/stretchr/%s")
t.SetIssue("testify")
})}
```
---
:zap: `ALLURE_TESTCASE_PATTERN` - Specifies the url pattern for your TestCases. Has no default value. **Mandatory**. Must
contain `%s`.If `ALLURE_TESTCASE_PATTERN` is not specified, the link will be read in its entirety.
Example:
```go
package provider_demoimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
)func TestSampleDemo(t *testing.T) {
runner.Run(t, "Just Link", func(t provider.T) {
t.SetTestCase("https://pkg.go.dev/github.com/stretchr/testify")
})runner.Run(t, "With Pattern", func(t provider.T) {
_ = os.Setenv("ALLURE_TESTCASE_PATTERN", "https://pkg.go.dev/github.com/stretchr/%s")
t.SetTestCase("testify")
})}
```
---
:zap: `ALLURE_LAUNCH_TAGS` - Sheds a list of tags that will be applied to each test by default. It has no default value.:information_source: **Tip:** `ALLURE_LAUNCH_TAGS` - Very handy to use with CI/CD. For example, you can define test groups in it by your
ci-jobs, or you can roll the name of a branch.---
:zap: `ALLURE_TESTPLAN_PATH` - describes path to your test plan json.:information_source: **Tip:** To use this feature you need to work with [Allure TestOps](https://docs.qameta.io/allure-testops/ecosystem/allurectl/#tests-rerun-and-selective-run-with-allurectl)
## :smirk: Going Deeper...
### pkg/allure
:page_facing_up: [pkg/allure documentation](./pkg/allure/README.md)
### pkg/framework
:page_facing_up: [pkg/framework documentation](./pkg/framework/README.md)
### cute
:full_moon_with_face: [You can find cute here!](https://github.com/ozontech/cute)
Cute - is library for simply creating HTTP tests in Go with Allure reports.
Main features:
:zap: Full integration with Allure
:zap: Expressive and intuitive syntax
:zap: Built-in JSON support
:zap: Custom asserts
:zap: One step to BDDCute can simply improve your allure-go testing experience! Try it :wink:
## :school_satchel: Few more examples
### [Async test](examples/async/async_step_test.go)
:rocket: **YES!** We really **can** run **parallel** tests in **suites**.
:rocket: Even with async steps.
:rocket: Example below.Test code:
```go
package asyncimport (
"fmt"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type AsyncSuiteStepDemo struct {
suite.Suite
}func (s *AsyncSuiteStepDemo) BeforeEach(t provider.T) {
t.Epic("Async")
t.Feature("Async Steps")
t.Tags("async", "suite", "steps")
}func (s *AsyncSuiteStepDemo) TestAsyncStepDemo1(t provider.T) {
t.Title("Async Test with async steps 1")t.Parallel()
t.WithNewAsyncStep("Async Step 1", func(ctx provider.StepCtx) {
ctx.WithNewParameters("Start", fmt.Sprintf("%s", time.Now()))
time.Sleep(3 * time.Second)
ctx.WithNewParameters("Stop", fmt.Sprintf("%s", time.Now()))
})t.WithNewAsyncStep("Async Step 2", func(ctx provider.StepCtx) {
ctx.WithNewParameters("Start", fmt.Sprintf("%s", time.Now()))
time.Sleep(3 * time.Second)
ctx.Logf("Step 2 Stopped At: %s", fmt.Sprintf("%s", time.Now()))
ctx.WithNewParameters("Stop", fmt.Sprintf("%s", time.Now()))
})
}
```Allure output:
![](.resources/example_async_test.png)
### [Test with nested steps](examples/suite_demo/step_tree_test.go):
Test code:
```go
package examplesimport (
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type StepTreeDemoSuite struct {
suite.Suite
}func (s *StepTreeDemoSuite) TestInnerSteps(t provider.T) {
t.Epic("Demo")
t.Feature("Inner Steps")
t.Title("Simple Nesting")
t.Description(`
Step A is parent step for Step B and Step C
Call order will be saved in allure report
A -> (B, C)`)t.Tags("Steps", "Nesting")
t.WithNewStep("Step A", func(ctx provider.StepCtx) {
ctx.NewStep("Step B")
ctx.NewStep("Step C")
})
}
```Output to Allure:
![](.resources/example_step_tree.png)
### [Test with Attachment](examples/suite_demo/attachments_test.go)
Test code:
```go
package examplesimport (
"encoding/json""github.com/ozontech/allure-go/pkg/allure"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type JSONStruct struct {
Message string `json:"message"`
}type AttachmentTestDemoSuite struct {
suite.Suite
}func (s *AttachmentTestDemoSuite) TestAttachment(t provider.T) {
t.Epic("Demo")
t.Feature("Attachments")
t.Title("Test Attachments")
t.Description(`
Test's test body and all steps inside can contain attachments`)t.Tags("Attachments", "BeforeAfter", "Steps")
attachmentText := `THIS IS A TEXT ATTACHMENT`
t.Attachment(allure.NewAttachment("Text Attachment if TestAttachment", allure.Text, []byte(attachmentText)))step := allure.NewSimpleStep("Step A")
var ExampleJson = JSONStruct{"this is JSON message"}
attachmentJSON, _ := json.Marshal(ExampleJson)
step.Attachment(allure.NewAttachment("Json Attachment for Step A", allure.JSON, attachmentJSON))
t.Step(step)
}
```Output to Allure:
![](.resources/example_attachments.png)
### [Run few parallel suites](examples/suite_demo/running_test.go)
Test code:
```go
package examplesimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type TestRunningDemoSuite struct {
suite.Suite
}func (s *TestRunningDemoSuite) TestBeforesAfters(t provider.T) {
t.Parallel()
// use RunInner to run suite of tests
s.RunSuite(t, new(BeforeAfterDemoSuite))
}func (s *TestRunningDemoSuite) TestFails(t provider.T) {
t.Parallel()
s.RunSuite(t, new(FailsDemoSuite))
}func (s *TestRunningDemoSuite) TestLabels(t provider.T) {
t.Parallel()
s.RunSuite(t, new(LabelsDemoSuite))
}func TestRunDemo(t *testing.T) {
// use RunSuites to run suite of suites
suite.RunSuite(t, new(TestRunningDemoSuite))
}
```Output to Allure:
![](.resources/example_multiple_suites_run.png)
### [Setup hooks](examples/suite_demo/befores_afters_test.go)
Test code:
```go
package examplesimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type BeforeAfterDemoSuite struct {
suite.Suite
}func (s *BeforeAfterDemoSuite) BeforeEach(t provider.T) {
t.NewStep("Before Test Step")
}func (s *BeforeAfterDemoSuite) AfterEach(t provider.T) {
t.NewStep("After Test Step")
}func (s *BeforeAfterDemoSuite) BeforeAll(t provider.T) {
t.NewStep("Before suite Step")
}func (s *BeforeAfterDemoSuite) AfterAll(t provider.T) {
t.NewStep("After suite Step")
}func (s *BeforeAfterDemoSuite) TestBeforeAfterTest(t provider.T) {
t.Epic("Demo")
t.Feature("BeforeAfter")
t.Title("Test wrapped with SetUp & TearDown")
t.Description(`
This test wrapped with SetUp and TearDown containert.`)t.Tags("BeforeAfter")
}func TestBeforesAfters(t *testing.T) {
t.Parallel()
suite.RunSuite(t, new(BeforeAfterDemoSuite))
}
```Output to Allure:
![](.resources/example_befores_afters.png)
### [XSkip](examples/suite_demo/fails_test.go)
Test code:
```go
package examplesimport (
"testing""github.com/stretchr/testify/require"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type DemoSuite struct {
suite.Suite
}func (s *DemoSuite) TestXSkipFail(t provider.T) {
t.Title("This test skipped by assert with message")
t.Description(`
This Test will be skipped with assert Error.
Error text: Assertion Failed`)
t.Tags("fail", "xskip", "assertions")t.XSkip()
t.Require().Equal(1, 2, "Assertion Failed")
}func TestDemoSuite(t *testing.T) {
t.Parallel()
suite.RunSuite(t, new(DemoSuite))
}
```Output to Allure:
![](.resources/example_xskip.png)
### [Parametrized Test](examples/suite_demo/new_parametrized_test.go)
Test code:
```go
package suite_demoimport (
"testing""github.com/jackc/fake"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type ParametrizedSuite struct {
suite.Suite
ParamCities []string
}func (s *ParametrizedSuite) BeforeAll(t provider.T) {
for i := 0; i < 10; i++ {
s.ParamCities = append(s.ParamCities, fake.City())
}
}func (s *ParametrizedSuite) TableTestCities(t provider.T, city string) {
t.Parallel()
t.Require().NotEmpty(city)
}func TestNewParametrizedDemo(t *testing.T) {
suite.RunSuite(t, new(ParametrizedSuite))
}
```Output to Allure:
![](.resources/example_table_test.png)
### [Setup test](examples/suite_demo/setup_test.go)
This feature allows you to extend your test setting up/tearing down functional
Test code:
```go
package suite_demoimport (
"context"
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type SetupSuite struct {
suite.Suite
}func (s *SetupSuite) TestMyTest(t provider.T) {
var (
v1 string
v2 int
ctx context.Context
)
t.WithTestSetup(func(t provider.T) {
t.WithNewStep("init v1", func(sCtx provider.StepCtx) {
v1 = "string"
sCtx.WithNewParameters("v1", v1)
})
t.WithNewStep("init v2", func(sCtx provider.StepCtx) {
v2 = 123
sCtx.WithNewParameters("v2", v2)
})
t.WithNewStep("init ctx", func(sCtx provider.StepCtx) {
ctx = context.Background()
sCtx.WithNewParameters("ctx", ctx)
})
})
defer t.WithTestTeardown(func(t provider.T) {
t.WithNewStep("Close ctx", func(sCtx provider.StepCtx) {
ctx.Done()
sCtx.WithNewParameters("ctx", ctx)
})
})
}func TestRunner(t *testing.T) {
suite.RunSuite(t, new(SetupSuite))
}
```Allure output:
![](.resources/example_setup_test.png)
### Prevent loosing allureID in test results
When suit fails at the setup stage (beforeAll), report will not contain `ALLURE_ID` field.
To prevent it you can use `GetAllureID(testName string) string` method for common tests and
`InitializeTestsParams()` method for parametrized tests.**Example for `GetAllureID` method:**
```go
package suite_demoimport (
"testing""github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type AllureIDSuite struct {
suite.Suite
}func (testSuit *AllureIDSuite) GetAllureID(testName string) string {
switch testName {
case "TestWithAllureIDFirst":
return "9001"
case "TestWithAllureIDSecond":
return "9002"
default:
return ""
}
}func (s *AllureIDSuite) BeforeAll(t provider.T) {
// code that can fail here
}func (s *AllureIDSuite) TestWithAllureIDFirst(t provider.T) {
// code of your test here
}func (s *AllureIDSuite) TestWithAllureIDSecond(t provider.T) {
// code of your test here
}func TestNewDemo(t *testing.T) {
suite.RunSuite(t, new(AllureIDSuite))
}```
**Example for `InitializeTestsParams` method:**
```go
package suite_demoimport (
"testing""github.com/jackc/fake"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)type CitiesParam struct {
allureID string
title string
value string
}func (p CitiesParam) GetAllureID() string {
return p.allureID
}
func (p CitiesParam) GetAllureTitle() string {
return p.title
}type ParametrizedSuite struct {
suite.Suite
ParamCities []CitiesParam
}func (s *ParametrizedSuite) InitializeTestsParams() {
s.ParamCities = make([]CitiesParam, 2)
s.ParamCities[0] = CitiesParam{
title: "Title for city test #1",
allureID: "101",
value: fake.City(),
}s.ParamCities[1] = CitiesParam{
title: "Title for city test #2",
allureID: "102",
value: fake.City(),
}
}func (s *ParametrizedSuite) BeforeAll(t provider.T) {
// setup suit here
}func (s *ParametrizedSuite) TableTestCities(t provider.T, city CitiesParam) {
t.Parallel()
t.Require().NotEmpty(city.value)
}func TestNewParametrizedDemo(t *testing.T) {
suite.RunSuite(t, new(ParametrizedSuite))
}
```