Testo is a modular, zero-dependency testing framework for Go. It has a unique plugin system which was inspired by Pytest. Plugins can generate reports, add new functionality, plan test execution and much more.
Testo started as an internal project at a large big-tech company and was recently open-sourced. It powers thousands of end-to-end tests daily at enterprise scale.
GitHub: github.com/ozontech/testo
Feedback and contributions are greatly appreciated!
go get github.com/ozontech/testo
It comes with its own VS Code extension for running tests in suites.
Features
- Plugins - adapt your tests to any scenario with features you need.
- Parametrized tests - define a test once, repeat it with different parameters.
- Parallel tests -
t.Parallel()just works. - Lifecycle hooks - before and after any suite, test & sub-test.
- Test annotations - attach static options to any test.
- Informative errors and traces.
- Suites, sub-tests & sub-suites - organize your tests the way you need.
- Test reflection - deeply inspect test’s meta-information.
- Caching - key-value storage persistent between test runs.
- Zero dependencies.
Example
package main
import (
"testing"
"github.com/ozontech/testo"
allure "github.com/ozontech/testo-allure"
"github.com/ozontech/testo-toppings/parallel"
)
type T struct {
*testo.T
// plugins:
*allure.PluginAllure // generate allure reports
*parallel.PluginParallel // make all tests parallel by default
}
func TestSingle(t *testing.T) {
testo.RunTest(t, func(t T) {
t.Log("hello")
})
}
func TestNamed(t *testing.T) {
t.Run("First test", testo.Test(func(t T) {
t.Log("greetings")
}))
t.Run("Second test", testo.Test(func(t T) {
t.Log("hola")
}))
}
func TestSuite(t *testing.T) {
testo.RunSuite(t, new(Functional))
}
type Functional struct {
testo.Suite[T]
}
func (Functional) TestSimple(t T) {
t.Log("hello")
}
// Parameterized test which will be executed for all combinations of A & B.
func (Functional) TestAdd(t T, p struct{ A, B int }) {
t.Log(p.A, p.B)
}
// Special CasesXxx methods
func (Functional) CasesA() []int {
return []int{1, 2, 3}
}
func (Functional) CasesB() []int {
return []int{100, 200}
}
