golang增强标准测试包功能的插件库Testify的使用

Golang增强标准测试包功能的插件库Testify的使用

Testify是一组为Golang设计的测试工具包,提供了许多工具来验证代码行为是否符合预期。

主要功能

  • 简易断言
  • 模拟对象
  • 测试套件接口和函数

assert包

assert包提供了一些有用的方法,可以让你编写更好的Go测试代码。

package yours

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestSomething(t *testing.T) {
	// 断言相等
	assert.Equal(t, 123, 123, "they should be equal")

	// 断言不等
	assert.NotEqual(t, 123, 456, "they should not be equal")

	// 断言nil(适用于错误检查)
	assert.Nil(t, object)

	// 断言非nil(当你期望有值时)
	if assert.NotNil(t, object) {
		// 现在我们确定object不是nil,可以安全地进行进一步断言
		assert.Equal(t, "Something", object.Value)
	}
}

如果你需要多次断言,可以使用以下方式:

package yours

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestSomething(t *testing.T) {
	assert := assert.New(t)

	// 断言相等
	assert.Equal(123, 123, "they should be equal")

	// 断言不等
	assert.NotEqual(123, 456, "they should not be equal")

	// 断言nil
	assert.Nil(object)

	// 断言非nil
	if assert.NotNil(object) {
		assert.Equal("Something", object.Value)
	}
}

require包

require包提供了与assert包相同的全局函数,但它们不是返回布尔结果,而是终止当前测试。这些函数必须从运行测试或基准函数的goroutine中调用,而不是从测试期间创建的其他goroutine中调用,否则可能会出现竞争条件。

mock包

mock包提供了一种简单的机制来编写模拟对象,可以在编写测试代码时替代真实对象。

package yours

import (
	"testing"

	"github.com/stretchr/testify/mock"
)

/*
  测试对象
*/

// MyMockedObject是一个模拟对象,实现了被测试代码依赖的接口
type MyMockedObject struct {
	mock.Mock
}

// DoSomething是MyMockedObject上的方法,实现了某个接口
// 它只是记录活动,并返回Mock对象告诉它的内容
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
	args := m.Called(number)
	return args.Bool(0), args.Error(1)
}

/*
  实际测试函数
*/

// TestSomething是一个示例,展示如何使用我们的测试对象
// 对我们正在测试的目标代码进行断言
func TestSomething(t *testing.T) {
	// 创建测试对象实例
	testObj := new(MyMockedObject)

	// 设置期望
	testObj.On("DoSomething", 123).Return(true, nil)

	// 调用我们正在测试的代码
	targetFuncThatDoesSomethingWithObj(testObj)

	// 断言期望已满足
	testObj.AssertExpectations(t)
}

suite包

suite包提供了你可能从更常见的面向对象语言中熟悉的功能。使用它,你可以构建一个测试套件作为结构体,在结构体上构建setup/teardown方法和测试方法,并像往常一样用’go test’运行它们。

// 基本导入
import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

// 定义套件,并从testify吸收内置的基本套件功能
type ExampleTestSuite struct {
	suite.Suite
	VariableThatShouldStartAtFive int
}

// 确保VariableThatShouldStartAtFive在每个测试前设置为5
func (suite *ExampleTestSuite) SetupTest() {
	suite.VariableThatShouldStartAtFive = 5
}

// 所有以"Test"开头的方法都作为套件中的测试运行
func (suite *ExampleTestSuite) TestExample() {
	assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
}

// 为了让'go test'运行这个套件,我们需要创建一个普通的测试函数
// 并将我们的套件传递给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 (已弃用)

保持最新

要更新Testify到最新版本,使用go get -u github.com/stretchr/testify

支持的Go版本

我们目前支持从1.19开始的最新主要Go版本。


更多关于golang增强标准测试包功能的插件库Testify的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang增强标准测试包功能的插件库Testify的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Testify - Go测试增强库

Testify 是一个流行的 Go 测试增强库,它扩展了标准库 testing 的功能,提供了更强大的断言、mock 功能和测试套件支持。下面我将详细介绍 Testify 的主要组件和使用方法。

1. 安装 Testify

go get github.com/stretchr/testify

2. 主要组件

2.1 assert 包 - 强大的断言

assert 包提供了丰富的断言方法,比标准库的 t.Failt.Error 更易用。

import (
    "testing"
    "github.com/stretchr/testify/assert"
)

func TestAdd(t *testing.T) {
    result := Add(1, 2)
    
    // 基本断言
    assert.Equal(t, 3, result, "they should be equal")
    assert.NotEqual(t, 4, result, "they should not be equal")
    assert.Nil(t, err)
    assert.NotNil(t, obj)
    
    // 布尔断言
    assert.True(t, isValid)
    assert.False(t, hasError)
    
    // 集合断言
    assert.Contains(t, "Hello World", "World")
    assert.Len(t, slice, 3)
    assert.ElementsMatch(t, []int{1,2,3}, []int{3,2,1})
    
    // 错误处理
    assert.NoError(t, err)
    assert.Error(t, err)
    assert.ErrorIs(t, err, io.EOF)
}

2.2 require 包 - 致命断言

require 包与 assert 类似,但在断言失败时会立即终止测试(调用 t.FailNow())。

import (
    "testing"
    "github.com/stretchr/testify/require"
)

func TestDivide(t *testing.T) {
    result, err := Divide(10, 2)
    require.NoError(t, err)  // 如果出错,立即终止测试
    require.Equal(t, 5, result)
}

2.3 suite 包 - 测试套件

suite 包提供了类似 xUnit 风格的测试套件功能,可以共享 setup 和 teardown 逻辑。

import (
    "testing"
    "github.com/stretchr/testify/suite"
)

type ExampleTestSuite struct {
    suite.Suite
    Value int
}

// 在每个测试前运行
func (suite *ExampleTestSuite) SetupTest() {
    suite.Value = 5
}

// 测试示例
func (suite *ExampleTestSuite) TestExample() {
    suite.Equal(5, suite.Value)
}

// 让go test运行这个测试套件
func TestExampleTestSuite(t *testing.T) {
    suite.Run(t, new(ExampleTestSuite))
}

2.4 mock 包 - 模拟对象

mock 包提供了创建模拟对象的能力,非常适合单元测试。

import (
    "testing"
    "github.com/stretchr/testify/mock"
)

// 定义模拟对象
type MyMockedObject struct {
    mock.Mock
}

// 模拟方法
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
    args := m.Called(number)
    return args.Bool(0), args.Error(1)
}

func TestSomething(t *testing.T) {
    // 创建模拟对象
    testObj := new(MyMockedObject)
    
    // 设置期望
    testObj.On("DoSomething", 123).Return(true, nil)
    
    // 调用被测代码
    result, err := testObj.DoSomething(123)
    
    // 断言
    assert.True(t, result)
    assert.Nil(t, err)
    
    // 验证期望是否满足
    testObj.AssertExpectations(t)
}

3. 高级用法

3.1 自定义断言消息

func TestCustomMessage(t *testing.T) {
    assert.Equal(t, 2, 1+1, "Math is broken!")
}

3.2 使用 assert.New 创建断言实例

func TestWithAssertInstance(t *testing.T) {
    assert := assert.New(t)
    
    // 现在可以省略第一个参数
    assert.Equal(3, Add(1, 2))
    assert.NotEqual(4, Add(1, 2))
}

3.3 HTTP 测试

func TestHTTPHandler(t *testing.T) {
    req := httptest.NewRequest("GET", "/hello", nil)
    w := httptest.NewRecorder()
    
    HelloHandler(w, req)
    
    resp := w.Result()
    assert.Equal(t, http.StatusOK, resp.StatusCode)
    
    body, _ := io.ReadAll(resp.Body)
    assert.Equal(t, "Hello, World!", string(body))
}

4. 最佳实践

  1. 对于需要继续执行的检查使用 assert,对于必须成功的检查使用 require
  2. 使用测试套件组织相关测试,共享 setup/teardown 逻辑
  3. 为 mock 对象设置清晰的期望,并验证它们是否被满足
  4. 保持断言消息简洁但信息丰富
  5. 考虑使用 assert.New(t) 简化大量断言的测试代码

Testify 通过提供这些强大的工具,使得 Go 的单元测试更加简洁、可读和强大。它已经成为 Go 生态系统中最受欢迎的测试辅助库之一。

回到顶部