stretchr/testify
GitHub: stretchr/testify
这是一个为 Go 语言开发提供断言、模拟对象和测试套件功能的工具包,旨在简化测试代码编写并提高可读性。
Stars: 25927 | Forks: 1699
# Testify - 汝当编写测试
[](https://github.com/stretchr/testify/actions/workflows/main.yml) [](https://goreportcard.com/report/github.com/stretchr/testify) [](https://pkg.go.dev/github.com/stretchr/testify)
Go 代码(golang)包集合,提供了许多工具来证明你的代码会按预期运行。
功能包括:
* [简单的断言](#assert-package)
* [模拟](#mock-package)
* [测试套件接口和函数](#suite-package)
开始使用:
* 使用 [一行代码](#installation) 安装 testify,或者 [用另一行代码更新它](#staying-up-to-date)
* 有关在 Go 中编写测试代码的介绍,请参阅 https://go.dev/doc/code#Testing
* 查看 API 文档 https://pkg.go.dev/github.com/stretchr/testify
* 使用 [testifylint](https://github.com/Antonboom/testifylint)(通过 [golangci-lint](https://golangci-lint.run/))来避免常见错误
* 关于[测试驱动开发 (TDD)](https://en.wikipedia.org/wiki/Test-driven_development)的一点介绍
## [`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") 包
`assert` 包提供了一些有用的方法,允许你在 Go 中编写更好的测试代码。
* 打印友好、易读的失败描述
* 允许编写可读性很强的代码
* 可以选择为每个断言添加注释信息
查看实际效果:
```
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
// assert equality
assert.Equal(t, 123, 123, "they should be equal")
// assert inequality
assert.NotEqual(t, 123, 456, "they should not be equal")
// assert for nil (good for errors)
assert.Nil(t, object)
// assert for not nil (good when you expect something)
if assert.NotNil(t, object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal(t, "Something", object.Value)
}
}
```
* 每个 assert 函数都将 `testing.T` 对象作为第一个参数。这就是它通过标准的 `go test` 功能输出错误的方式。
* 每个 assert 函数返回一个布尔值,指示断言是否成功,如果你想在特定条件下继续进行更多断言,这很有用。
如果你要进行多次断言,请使用以下方法:
```
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
assert := assert.New(t)
// assert equality
assert.Equal(123, 123, "they should be equal")
// assert inequality
assert.NotEqual(123, 456, "they should not be equal")
// assert for nil (good for errors)
assert.Nil(object)
// assert for not nil (good when you expect something)
if assert.NotNil(object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal("Something", object.Value)
}
}
```
## [`require`](https://pkg.go.dev/github.com/stretchr/testify/require "API documentation") 包
`require` 包提供与 `assert` 包相同的全局函数,但它们不返回布尔结果,而是终止当前测试。
这些函数必须在运行测试或基准函数的 goroutine 中调用,而不是在测试期间创建的其他 goroutine 中调用。
否则可能会发生竞态条件。
有关详细信息,请参阅 [t.FailNow](https://pkg.go.dev/testing#T.FailNow)。
## [`mock`](https://pkg.go.dev/github.com/stretchr/testify/mock "API documentation") 包
`mock` 包提供了一种机制,可以轻松编写模拟对象,在编写测试代码时可以用它们代替真实对象。
一个示例测试函数测试一段依赖于外部对象 `testObj` 的代码,可以设置预期(testify)并断言它们确实发生了:
```
package yours
import (
"testing"
"github.com/stretchr/testify/mock"
)
/*
Test objects
*/
// MyMockedObject is a mocked object that implements an interface
// that describes an object that the code I am testing relies on.
type MyMockedObject struct {
mock.Mock
}
// DoSomething is a method on MyMockedObject that implements some interface
// and just records the activity, and returns what the Mock object tells it to.
//
// In the real object, this method would do something useful, but since this
// is a mocked object - we're just going to stub it out.
//
// NOTE: This method is not being tested here, code that uses this object is.
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
args := m.Called(number)
return args.Bool(0), args.Error(1)
}
/*
Actual test functions
*/
// TestSomething is an example of how to use our test object to
// make assertions about some target code we are testing.
func TestSomething(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations
testObj.On("DoSomething", 123).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
}
// TestSomethingWithPlaceholder is a second example of how to use our test object to
// make assertions about some target code we are testing.
// This time using a placeholder. Placeholders might be used when the
// data being passed in is normally dynamically generated and cannot be
// predicted beforehand (eg. containing hashes that are time sensitive)
func TestSomethingWithPlaceholder(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
}
// TestSomethingElse2 is a third example that shows how you can use
// the Unset method to cleanup handlers and then add new ones.
func TestSomethingElse2(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations with a placeholder in the argument list
mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
// remove the handler now so we can add another one that takes precedence
mockCall.Unset()
// return false now instead of true
testObj.On("DoSomething", mock.Anything).Return(false, nil)
testObj.AssertExpectations(t)
}
```
有关如何编写模拟代码的更多信息,请查看 [`mock` 包的 API 文档](https://pkg.go.dev/github.com/stretchr/testify/mock)。
你也可以使用 [mockery 工具](https://vektra.github.io/mockery/latest/) 针对接口自动生成模拟代码,从而使使用模拟变得更加快捷。
## [`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") 包
`suite` 包提供了你可能从更常见的面向对象语言中熟悉的功能。使用它,你可以将测试套件构建为一个结构体,在结构体上构建 setup/teardown 方法和测试方法,并像往常一样使用 'go test' 运行它们。
下面的示例展示了一个套件:
```
// Basic imports
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including a T() method which
// returns the current testing context
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
}
// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
}
// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
}
```
要查看使用 suite 包提供的所有功能的更完整示例,请查看我们的 [示例测试套件](https://github.com/stretchr/testify/blob/master/suite/suite_test.go)
有关编写套件的更多信息,请查看 [`suite` 包的 API 文档](https://pkg.go.dev/github.com/stretchr/testify/suite)。
`Suite` 对象具有断言方法:
```
// Basic imports
import (
"testing"
"github.com/stretchr/testify/suite"
)
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including assertion methods.
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
}
// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
}
// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
suite.Equal(suite.VariableThatShouldStartAtFive, 5)
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
}
```
# 安装
要安装 Testify,请使用 `go get`:
```
go get github.com/stretchr/testify
```
这将使以下包可用:
```
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
github.com/stretchr/testify/mock
github.com/stretchr/testify/suite
github.com/stretchr/testify/http (deprecated)
```
使用此模板将 `testify/assert` 包导入到你的代码中:
```
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
assert.True(t, true, "True is true!")
}
```
# 保持最新
要将 Testify 更新到最新版本,请使用 `go get -u github.com/stretchr/testify`。
# 支持的 Go 版本
我们目前支持从 1.19 开始最新的主要 Go 版本。
# 许可证
本项目根据 MIT 许可证的条款获得许可。
标签:assert, DNS解析, EVTX分析, Golang, Go语言, mock, Mock框架, suite, TDD, 单元测试, 安全编程, 开源项目, 断言库, 日志审计, 测试套件, 测试工具, 测试辅助, 测试驱动开发, 程序破解, 软件开发