Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ A collection of small, miscellaneous plugins for [Testo framework](https://githu
- [Rerun](./rerun) - adds `--last-failed`-like behaviour from Pytest to Testo. Makes it possible to rerun only failed tests.
- [XFail](./xfail) - adds `t.XFail()` method to mark a test as "expected to fail".
- [Parallel](./parallel) - marks all tests as parallel by default.
- [Environment](./environment) - loads environment variables from `.env` files for testing.

See also [Allure plugin for Testo](https://github.com/ozontech/testo-allure) - visualize results of a test run with [Allure Report](https://allurereport.org/).
70 changes: 70 additions & 0 deletions environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Testo Environment Plugin

A testo plugin that loads environment variables from `.env` files for testing.

## Usage

```go
import (
"github.com/ozontech/testo"
"github.com/ozontech/testo-toppings/environment"
"github.com/ozontech/testo/testoplugin"
)

func Test(t *testing.T) {
options := []testoplugin.Option{
environment.WithEnvironments(".env", "config.env"),
}

testo.RunSuite(t, new(Suite), options...)
}
```

## Features

- Loads environment variables from `.env` files
- Sets environment variables in `BeforeAll` hook
- Supports multiple `.env` files (later files overwrite earlier ones)
- Handles comments (`#`) and empty lines
- Defaults to loading `.env` from the current directory if no files specified

## Default File Loading

By default, the plugin loads `.env` from the current directory when no files are specified:
```go
func Test(t *testing.T) {
options := []testoplugin.Option{
environment.WithEnvironments(), // Loads .env automatically
}
testo.RunSuite(t, new(Suite), options...)
}
```

## .env File Format

```
# This is a comment
KEY1=VALUE1
KEY2="quoted value"
KEY3=VALUE3
```

## Multiple Files

When multiple files are provided, values from later files overwrite earlier ones:
```go
environment.WithEnvironments("base.env", "override.env")
```

In this case, `override.env` values take precedence over `base.env` values.

## Custom Default Files

You can customize the default files loaded when no explicit files are specified:
```go
package environment

var DefaultEnviroments = []string{".env", "config.env"}
```

This will load both `.env` and `config.env` when `WithEnvironments()` is called without arguments.
4 changes: 4 additions & 0 deletions environment/examples/01_basic/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MAKEFLAGS += --always-make

test:
go test . -v -tags example -count=1
47 changes: 47 additions & 0 deletions environment/examples/01_basic/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build example

package main

import (
"os"
"testing"

"github.com/ozontech/testo"
"github.com/ozontech/testo-toppings/environment"
"github.com/ozontech/testo/testoplugin"
)

type T struct {
*testo.T
*environment.PluginEnvironment
}

type Suite struct{ testo.Suite[T] }

func (Suite) TestA(t T) {
testo.Run(t, "KEY-VALUE-1", func(t T) {
val := os.Getenv("KEY1")
if val != "VALUE1" {
t.FailNow()
}
})
}

func (Suite) TestB(t T) {
testo.Run(t, "KEY-VALUE-2", func(t T) {
val := os.Getenv("KEY2")
if val != "VALUE2" {
t.FailNow()
}
})

}

func Test(t *testing.T) {

options := []testoplugin.Option{
environment.WithEnvironments(".env"),
}

testo.RunSuite(t, new(Suite), options...)
}
4 changes: 4 additions & 0 deletions environment/examples/02_many_files/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MAKEFLAGS += --always-make

test:
go test . -v -tags example -count=1
2 changes: 2 additions & 0 deletions environment/examples/02_many_files/basic.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
KEY1=VALUE1
KEY2=VALUE2
46 changes: 46 additions & 0 deletions environment/examples/02_many_files/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//go:build example

package main

import (
"os"
"testing"

"github.com/ozontech/testo"
"github.com/ozontech/testo-toppings/environment"
"github.com/ozontech/testo/testoplugin"
)

type T struct {
*testo.T
*environment.PluginEnvironment
}

type Suite struct{ testo.Suite[T] }

func (Suite) TestA(t T) {
testo.Run(t, "KEY-VALUE-1", func(t T) {
val := os.Getenv("KEY1")
if val != "STAND_VALUE1" {
t.FailNow()
}
})

testo.Run(t, "KEY-VALUE-2", func(t T) {
val := os.Getenv("KEY2")
if val != "VALUE2" {
t.FailNow()
}
})
}

func Test(t *testing.T) {
options := []testoplugin.Option{
environment.WithEnvironments(
"basic.env",
"stand.env",
),
}

testo.RunSuite(t, new(Suite), options...)
}
2 changes: 2 additions & 0 deletions environment/examples/02_many_files/stand.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
KEY1=STAND_VALUE1
KEY2=VALUE2
4 changes: 4 additions & 0 deletions environment/examples/03_set_defaults/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MAKEFLAGS += --always-make

test:
go test . -v -tags example -count=1
2 changes: 2 additions & 0 deletions environment/examples/03_set_defaults/default.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
KEY1=VALUE1
KEY2=VALUE2
47 changes: 47 additions & 0 deletions environment/examples/03_set_defaults/suite_a_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build example

package main

import (
"os"
"testing"

"github.com/ozontech/testo"
"github.com/ozontech/testo-toppings/environment"
"github.com/ozontech/testo/testoplugin"
)

func init() {
environment.DefaultEnviroments = []string{"default.env"}
}

type T struct {
*testo.T
*environment.PluginEnvironment
}

type SuiteA struct{ testo.Suite[T] }

func (SuiteA) TestA(t T) {
testo.Run(t, "KEY-VALUE-1", func(t T) {
val := os.Getenv("KEY1")
if val != "VALUE1" {
t.FailNow()
}
})

testo.Run(t, "KEY-VALUE-2", func(t T) {
val := os.Getenv("KEY2")
if val != "VALUE2" {
t.FailNow()
}
})
}

func TestA(t *testing.T) {
options := []testoplugin.Option{
environment.WithEnvironments(),
}

testo.RunSuite(t, new(SuiteA), options...)
}
38 changes: 38 additions & 0 deletions environment/examples/03_set_defaults/suite_b_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build example

package main

import (
"os"
"testing"

"github.com/ozontech/testo"
"github.com/ozontech/testo-toppings/environment"
"github.com/ozontech/testo/testoplugin"
)

type SuiteB struct{ testo.Suite[T] }

func (SuiteB) TestA(t T) {
testo.Run(t, "KEY-VALUE-1", func(t T) {
val := os.Getenv("KEY1")
if val != "VALUE1" {
t.FailNow()
}
})

testo.Run(t, "KEY-VALUE-2", func(t T) {
val := os.Getenv("KEY2")
if val != "VALUE2" {
t.FailNow()
}
})
}

func TestB(t *testing.T) {
options := []testoplugin.Option{
environment.WithEnvironments(),
}

testo.RunSuite(t, new(SuiteA), options...)
}
17 changes: 17 additions & 0 deletions environment/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package environment

import "github.com/ozontech/testo/testoplugin"

type option func(p *PluginEnvironment)

// WithEnvironments specifies which .env files to load.
// Later files overwrite earlier files for the same environment variable.
// If no files are specified, defaults to loading .env from the current directory.
func WithEnvironments(filenames ...string) testoplugin.Option {
return testoplugin.Option{
Value: option(func(p *PluginEnvironment) {
p.filenames = filenames
}),
Propagate: true,
}
}
Loading