gunit

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2023 License: MIT, MIT Imports: 14 Imported by: 0

README

声明:这个项目是基于 smarty/gunit 改造的,原作者已经不维护所以移到本仓库继续更新。

gunit

gunit,又一个用于Go语言的测试工具。

不要再来了...(GoConvey已经够疯狂了...但还挺酷,好吧我会关注一下...)

等等,这个工具有一些非常有趣的特性。它是由内置测试包提供的好东西、GoConvey 项目中您所熟悉和喜爱的断言xUnit 测试风格(第一个真正的Go单元测试框架)的混合体,所有这些都与go test紧密结合在一起。

编写

啰哩啰嗦,,好吧。那么,为什么不只是使用标准的"testing"包呢?这个gunit有什么优势?

由"testing"包和go test工具建立的约定只允许在局部函数范围内:

func TestSomething(t *testing.T) {
	// 巴拉 巴拉 巴拉
}

这种有限的作用域使得共享方法和数据变得麻烦。如果试图保持测试简洁而短小,可能会变得混乱。以下展示了如何使用gunit 编写*_test.go文件:


package examples

import (
	"time"
	"testing"

	"github.com/smarty/assertions/should"
	"github.com/bugVanisher/gunit"
)

func TestExampleFixture(t *testing.T) {
	gunit.Run(new(ExampleFixture), t)
}

type ExampleFixture struct {
	*gunit.Fixture // Required: Embedding this type is what makes the magic happen.

	// Declare useful state here (probably the stuff being tested, any fakes, etc...).
}

func (this *ExampleFixture) SetupStuff() {
	// This optional method will be executed before each "Test"
	// method (because it starts with "Setup").
}
func (this *ExampleFixture) TeardownStuff() {
	// This optional method will be executed after each "Test"
	// method (because it starts with "Teardown"), even if the test method panics.
}

func (this *ExampleFixture) FixtureSetupStuff() {
	// This optional method will be executed before all "Test"
	// method (because it starts with "FixtureSetup").
}
func (this *ExampleFixture) FixtureTeardownStuff() {
	// This optional method will be executed after all "Test"
	// method (because it starts with "FixtureTeardown"), even if any test method panics.
}

// This is an actual test case:
func (this *ExampleFixture) TestWithAssertions() {
	// Here's how to use the functions from the `should`
	// package at github.com/smarty/assertions/should
	// to perform assertions:
	this.So(42, should.Equal, 42)
	this.So("Hello, World!", should.ContainSubstring, "World")
}

func (this *ExampleFixture) SkipTestWithNothing() {
	// Because this method's name starts with 'Skip', it will be skipped.
}

func (this *ExampleFixture) LongTestSlowOperation() {
	// Because this method's name starts with 'Long', it will be skipped if `go test` is run with the `short` flag.
	time.Sleep(time.Hour)
	this.So(true, should.BeTrue)
}

所以,你只会看到一个传统的测试函数,而且只有一行代码(当然,还有一个结构体和它的方法)。这是怎么回事?

gunit允许用例编写者使用一个_结构体_"封装"一组相关测试用例,类似于xUnit 。这使得进行前置和后置行为变得更简单,因为测试的所有状态可以声明为嵌入gunit包中的Fixture 类型的结构体字段。只需创建一个Test函数,并将fixture结构体的新实例与* testing.T一起传递给gunit的Run函数,它将运行所有已定义的Test方法以及Setup和Teardown方法。另外,还可以使用FixtureSetup和FixtureTeardown方法在所有测试执行之前或之后定义一些操作。

核心特性

  • xUnit风格:完整支持 Go 语言的 xUnit 风格用例编写
  • 同时支持串行和并行:Fixture粒度的串行、并行控制,大大提高执行效率
  • 丰富断言支持:提供多种断言方式
  • Readable测试报告:以包为单位组织报告,查看和定位简洁高效
  • 复杂场景:可根据实际情况继承Fixture,实现业务级的接口、UI自动化测试

引用

import (
    "github.com/bugVanisher/gunit"
)

日志打印

使用fixture Logger中的Log/Debug/Info/Warn/Error方法打印日志,如下

type MyFixture struct {
    *gunit.Fixture
}
// 所有Test方法执行前执行
func (g *MyFixture) FixtureSetup() {
    g.GetLogger().Info().Msg("in FixtureSetup...")
}

// 所有Test方法执行后执行
func (g *MyFixture) FixtureTeardown() {
    g.GetLogger().Info().Msg("in FixtureTearDown...")
}

// 每一个Test方法执行前执行
func (g *MyFixture) Setup() {
    g.WithLogger(c.T()).Info().Msg("in test setup...")
}

// 每一个Test方法执行后执行
func (g *MyFixture) Teardown() {
    g.GetLogger().Info().Msg("in test teardown...")
}

// 真正的测试方法A
func (g *MyFixture) TestA() {
    g.GetLogger().Description("这是TestA")
    g.GetLogger().Info().Msg("hello TestA...")
}

// 真正的测试方法B
func (g *MyFixture) TestB() {
    g.GetLogger().Description("这是TestB")
    g.GetLogger().Info().Msg("hello TestB...")
}

必须调用Msg或Msgf才能输出!

并发执行

默认情况下,所有fixture的方法都会并行运行,因为它们应该是独立的,但如果由于某种原因有需要按顺序运行fixture,可以向Run() 方法传入参数gunit.Options.SequentialTestCases(),例如在下面的例子中,这样fixture中的Test*方法将会按照ASCII码顺序执行。

func TestExampleFixture(t *testing.T) {
    gunit.Run(new(ExampleFixture), t, gunit.Options.SequentialTestCases())
}

Examples


对于JetBrains IDE的用户,以下是可以使用的LiveTemplate,用于生成新fixture的脚手架代码:

  • Abbreviation: fixture
  • Description: 生成 gunit Fixture 脚手架代码
  • Template Text:
func Test$NAME$(t *testing.T) {
    gunit.Run(new($NAME$), t)
}

type $NAME$ struct {
    *gunit.Fixture
}

func (this *$NAME$) Setup() {
}

func (this *$NAME$) FixtureSetup() {
}

func (this *$NAME$) FixtureTeardown() {
}

func (this *$NAME$) Test$END$() {
}



执行&报告

单独执行

go test ./testcases/... -v

执行并生成报告

首次生成报告,先安装报告生成工具

go get github.com/bugVanisher/gunit-test-report

然后执行

go test ./testcases/... -json | gunit-test-report

将会在当前目录生成test_report.html报告。

Documentation

Overview

Package gunit provides "testing" package hooks and convenience functions for writing tests in an xUnit style. See the README file and the examples folder for examples.

Index

Constants

View Source
const (
	Test       = "FixtureTestName"
	Package    = "FixturePackageName"
	Title      = "FixtureTestTitle"
	RequestApi = "FixtureRequestApi"
)
View Source
const FixtureParallel = "FixtureParallel"

Variables

View Source
var Options singleton

Functions

func Run

func Run(fixture interface{}, t *testing.T, options ...option)

Run receives an instance of a struct that embeds *Fixture. The struct definition may include Setup*, Teardown*, FixtureSetup*, FixtureTeardown* and Test* methods which will be run as an xUnit-style test fixture.

Types

type Fixture

type Fixture struct {
	// contains filtered or unexported fields
}

Fixture keeps track of test status (failed, passed, skipped) and handles custom logging for xUnit style tests as an embedded field. The Fixture itself and it's *testing.T control the test flow.

func (*Fixture) Assert

func (f *Fixture) Assert(condition bool, messages ...string) bool

Assert tests a boolean which, if not true, marks the current test case as failed and prints the provided message.

func (*Fixture) AssertDeepEqual

func (f *Fixture) AssertDeepEqual(expected, actual interface{}) bool

func (*Fixture) AssertEqual

func (f *Fixture) AssertEqual(expected, actual interface{}) bool

func (*Fixture) AssertSprintEqual

func (f *Fixture) AssertSprintEqual(expected, actual interface{}) bool

func (*Fixture) AssertSprintfEqual

func (f *Fixture) AssertSprintfEqual(expected, actual interface{}, format string) bool

func (*Fixture) Errorf added in v1.1.0

func (f *Fixture) Errorf(format string, args ...interface{})

func (*Fixture) Fail added in v1.1.0

func (f *Fixture) Fail()

func (*Fixture) Failed

func (f *Fixture) Failed() bool

func (*Fixture) FatalStop added in v1.1.0

func (f *Fixture) FatalStop(args ...interface{})

FatalStop stop the test right now and the tests behind it will be skipped in SequentialTestCases mode.

func (*Fixture) FatalfStop added in v1.1.0

func (f *Fixture) FatalfStop(format string, args ...interface{})

func (*Fixture) GetLogger

func (f *Fixture) GetLogger() *Logger

func (*Fixture) Name

func (f *Fixture) Name() string

func (*Fixture) Run

func (f *Fixture) Run(name string, test func(fixture *Fixture))

Run is analogous to *testing.T.Run and allows for running subtests from test fixture methods (such as for table-driven tests).

func (*Fixture) SkipNow added in v1.1.0

func (f *Fixture) SkipNow()

func (*Fixture) So

func (f *Fixture) So(actual interface{}, assert assertion, expected ...interface{}) bool

So is a convenience method for reporting assertion failure messages, from the many assertion functions found in github.com/smarty/assertions/should. Example: this.So(actual, should.Equal, expected)

func (*Fixture) T

func (f *Fixture) T() TestingT

T exposes the TestingT (*testing.T) instance.

func (*Fixture) Write

func (f *Fixture) Write(p []byte) (int, error)

Write implements io.Writer. There are rare times when this is convenient (debugging via `log.SetOutput(fixture)`).

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

func (*Logger) Debug

func (f *Logger) Debug() *zerolog.Event

func (*Logger) Description

func (f *Logger) Description(desc string)

func (*Logger) Error added in v1.1.0

func (f *Logger) Error() *zerolog.Event

func (*Logger) Info

func (f *Logger) Info() *zerolog.Event

func (*Logger) Log

func (f *Logger) Log() *zerolog.Event

func (*Logger) Warn

func (f *Logger) Warn() *zerolog.Event

type TestingT

type TestingT interface {
	Helper()
	Name() string
	Log(args ...interface{})
	Failed() bool
}

TestingT represents the functional subset from *testing.T needed by Fixture.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL