【Golang星辰图】构建健壮应用的秘籍:探索Go语言中最强大的测试工具库
精进单元测试:探秘Go语言中流行的测试框架和工具
前言
提高软件质量和稳定性是每个开发人员的目标之一。而单元测试是保证代码质量的重要手段之一,可以帮助我们检查代码是否按预期工作,并提早发现潜在的bug。Go语言提供了丰富的测试框架和工具,本文将为你介绍Go语言中几个流行的测试框架和工具,帮助你更好地编写单元测试。
欢迎订阅专栏:Golang星辰图
文章目录
- 精进单元测试:探秘Go语言中流行的测试框架和工具
- 前言
- 1. testing库
- 1.1 基本概述
- 1.2 测试函数
- 1.2.1 命名规则
- 1.2.2 函数签名
- 1.3 子测试和子测试函数
- 1.4 示例和基准测试
- 1.5 测试覆盖率分析
- 1.6 并发测试
- 1.7 表格驱动测试
- 1.8 Mock测试
- 2. testify库
- 2.1 基本概述
- 2.2 测试函数
- 2.2.1 命名规则
- 2.2.2 函数签名
- 2.3 子测试和子测试函数
- 2.4 示例和基准测试
- 2.5 测试覆盖率分析
- 2.6 并发测试
- 2.7 表格驱动测试
- 2.8 Mock测试
- 3. ginkgo库
- 3.1 基本概述
- 3.2 测试函数
- 3.2.1 命名规则
- 3.2.2 函数签名
- 3.3 子测试和子测试函数
- 3.4 示例和基准测试
- 3.5 测试覆盖率分析
- 3.6 并发测试
- 3.7 表格驱动测试
- 3.8 Mock测试
- 4. gocheck库
- 4.1 基本概述
- 4.2 测试函数
- 4.2.1 命名规则
- 4.2.2 函数签名
- 4.3 子测试和子测试函数
- 4.4 Suite和SuiteSetUp
- 4.5 跳过测试
- 4.6 测试覆盖率
- 5. gomega库
- 5.1 基本概述
- 5.2 安装
- 5.3 使用
- 5.4 匹配器
- 5.5 自定义匹配器
- 6. goconvey库
- 6.1 基本概述
- 6.2 安装
- 6.3 使用
- 6.4 辅助函数
- 6.5 配置
- 总结
1. testing库
testing 是 Go 语言标准库中的测试框架,提供了基本的测试功能,包括测试函数、子测试和子测试函数、示例和基准测试、测试覆盖率分析、并发测试、表格驱动测试和 Mock 测试等。
1.1 基本概述
testing 库是 Go 语言标准库中的测试框架,用于对 Go 代码进行自动化测试。testing 库提供了一系列的测试函数,用于测试代码的正确性和性能。测试函数通常以 Test
开头,接受一个 *testing.T
类型的参数,用于报告测试结果和错误信息。
以下是一个简单的测试函数示例:
package mainimport ("testing"
)func TestAdd(t *testing.T) {got := Add(2, 3)want := 5if got != want {t.Errorf("got %d, want %d", got, want)}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们测试了 Add
函数的正确性。测试函数 TestAdd
接受一个 *testing.T
类型的参数,用于报告测试结果。我们通过 got
和 want
两个变量来比较期望值和实际值,如果两者不相等,则调用 t.Errorf
函数报告错误信息。
1.2 测试函数
1.2.1 命名规则
测试函数必须以 Test
开头,接受一个 *testing.T
类型的参数,并且不能有任何返回值。测试函数必须放在要测试的包的 _test.go
文件中,否则不会被测试框架识别。
1.2.2 函数签名
测试函数的函数签名如下:
func TestName(t *testing.T)
其中,Name
是测试函数的名称,通常为要测试的函数或方法的名称。t
是一个指向 testing.T
类型的指针,用于报告测试结果和错误信息。
1.3 子测试和子测试函数
子测试和子测试函数是 testing 库中的高级测试功能,用于对测试用例进行分组和子分组,以更好地组织和管理测试代码。子测试函数可以嵌套在其他子测试函数中,形成一个树状结构。子测试和子测试函数可以共享测试数据和测试逻辑,提高测试代码的复用性和可维护性。
以下是一个子测试函数示例:
package mainimport ("testing""testing/quick"
)func TestAdd(t *testing.T) {t.Run("normal case", func(t *testing.T) {got := Add(2, 3)want := 5if got != want {t.Errorf("got %d, want %d", got, want)}})t.Run("edge case", func(t *testing.T) {got := Add(0, 0)want := 0if got != want {t.Errorf("got %d, want %d", got, want)}})t.Run("property testing", func(t *testing.T) {f := func(x, y int) bool {return Add(x, y) == x+y}if err := quick.Check(f, nil); err != nil {t.Error(err)}})
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 t.Run
函数定义了三个子测试函数,分别测试了 Add
函数的正常情况、边界情况和属性测试。每个子测试函数都接受一个 *testing.T
类型的参数,用于报���测试结果和错误信息。子测试函数可以嵌套在其他子测试函数中,形成一个树状结构。
1.4 示例和基准测试
示例和基准测试是 testing 库中的高级测试功能,用于展示函数的使用方法和测试函数的性能。示例函数以 Example
开头,接受一个 *testing.T
类型的参数,用于展示函数的使用方法。基准测试函数以 Benchmark
开头,接受一个 *testing.B
类型的参数,用于测试函数的性能。
以下是一个示例函数示例:
package mainimport ("fmt""testing"
)func ExampleAdd() {got := Add(2, 3)fmt.Println(got)// Output: 5
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 ExampleAdd
函数展示了 Add
函数的使用方法。示例函数以 Example
开头,接受一个 *testing.T
类型的参数,用于展示函数的使用方法。示例函数的输出会被测试框架捕获并打印到控制台上。
以下是一个基准测试函数示例:
package mainimport ("testing"
)func BenchmarkAdd(b *testing.B) {for i := 0; i < b.N; i++ {Add(2, 3)}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 BenchmarkAdd
函数测试了 Add
函数的性能。基准测试函数以 Benchmark
开头,接受一个 *testing.B
类型的参数,用于测试函数的性能。基准测试函数会运行多次,以获取平均性能数据。
1.5 测试覆盖率分析
测试覆盖率分析是测试过程中非常重要的环节,用于评估测试用例的质量和测试代码的完整性。testing 库提供了 go test -cover
命令来进行测试覆盖率分析,该命令会输出被测试代码的覆盖率数据。
以下是一个测试覆盖率分析示例:
package mainimport ("testing"
)func TestAdd(t *testing.T) {got := Add(2, 3)want := 5if got != want {t.Errorf("got %d, want %d", got, want)}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 go test -cover
命令进行测试覆盖率分析。测试覆盖率分析结果如下:
$ go test -cover
PASS
coverage: 100.0% of statements
ok github.com/username/project 0.002s
从结果可以看出,被测试代码的覆盖率为 100%,说明测试用例的质量较好,测试代码的完整性较高。
1.6 并发测试
并发测试是 testing 库中的高级测试功能,用于测试并发代码的正确性和性能。testing 库提供了 t.Parallel()
函数来启用并发测试,该函数会告诉测试框架可以并发运行测试用例。
以下是一个并发测试示例:
package mainimport ("sync""testing"
)func TestCounter(t *testing.T) {t.Parallel()counter := NewCounter()var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()counter.Inc()}()go func() {defer wg.Done()counter.Inc()}()wg.Wait()got := counter.Value()want := 2if got != want {t.Errorf("got %d, want %d", got, want)}
}type Counter struct {value intmutex sync.Mutex
}func NewCounter() *Counter {return &Counter{}
}func (c *Counter) Inc() {c.mutex.Lock()defer c.mutex.Unlock()c.value++
}func (c *Counter) Value() int {c.mutex.Lock()defer c.mutex.Unlock()return c.value
}
在这个示例中,我们使用了 t.Parallel()
函数启用了并发测试。我们测试了一个并发计数器的正确性,该计数器使用了 sync.Mutex
来保证线程安全。在测试函数中,我们使用了 sync.WaitGroup
来等待所有 Goroutine 运行完毕。
1.7 表格驱动测试
表格驱动测试是 testing 库中的高级测试功能,用于对多组测试用例进行批量测试。表格驱动测试可以大大简化测试代码,提高测试代码的复用性和可维护性。
以下是一个表格驱动测试示例:
package mainimport ("testing"
)func TestAdd(t *testing.T) {cases := []struct {x, y, want int}{{2, 3, 5},{0, 0, 0},{-1, 1, 0},}for _, c := range cases {got := Add(c.x, c.y)if got != c.want {t.Errorf("got %d, want %d", got, c.want)}}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了表格驱动测试对 Add
函数进行了批量测试。我们定义了一个包含多组测试用例的结构体数组,每个测试用例都包含了 x
、y
和 want
三个字段。在测试函数中,我们遍历了所有的测试用例,并对每个测试用例进行了测试。
1.8 Mock测试
Mock 测试是 testing 库中的高级测试功能,用于模拟依赖组件的行为,以隔离被测试代码。Mock 测试可以大大提高测试代码的可靠性和可维护性。
以下是一个 Mock 测试示例:
package mainimport ("testing""github.com/stretchr/testify/mock"
)type UserService interface {GetUser(id int) (*User, error)
}type User struct {ID intName string
}type UserController struct {UserService UserService
}func (c *UserController) GetUser(id int) (*User, error) {return c.UserService.GetUser(id)
}type MockUserService struct {mock.Mock
}func (m *MockUserService) GetUser(id int) (*User, error) {args := m.Called(id)return args.Get(0).(*User), args.Error(1)
}func TestUserController_GetUser(t *testing.T) {userService := new(MockUserService)userService.On("GetUser", 1).Return(&User{ID: 1, Name: "Tom"}, nil)controller := &UserController{UserService: userService}user, err := controller.GetUser(1)if err != nil {t.Fatal(err)}if user.Name != "Tom" {t.Errorf("got %s, want Tom", user.Name)}userService.AssertExpectations(t)
}
在这个示例中,我们使用了 Mock 测试对 UserController
进行了测试。我们定义了一个 UserService
接口,用于模拟用户服务的行为。我们还定义了一个 MockUserService
结构体,用于实现 UserService
接口,并使用 testify/mock
库来模拟 UserService
的行为。在测试函数中,我们使用了 MockUserService
来模拟用户服务的行为,并对 UserController
进行了测试。
2. testify库
testify 是 Go 语言中最常用的测试库之一,提供了丰富的断言函数、模拟对象和测试套件等测试功能。testify 库的设计目标是提供一套简单易用、功能强大、可扩展性好的测试工具,以帮助开发者更高效地进行单元测试和集成测试。
2.1 基本概述
testify 库是一个第三方的 Go 测试库,用于对 Go 代码进行自动化测试。testify 库提供了一系列的测试工具,包括断言函数、模拟对象和测试套件等,用于帮助开发者更高效地进行单元测试和集成测试。
2.2 测试函数
2.2.1 命名规则
testify 库中的测试函数命名规则与 testing 库中的测试函数命名规则类似,必须以 Test
开头,接受一个 *testing.T
类型的参数,并且不能有任何返回值。测试函数必须放在要测试的包的 _test.go
文件中,否则不会被测试框架识别。
2.2.2 函数签名
testify 库中的测试函数的函数签名如下:
func TestName(t *testing.T)
其中,Name
是测试函数的名称,通常为要测试的函数或方法的名称。t
是一个指向 testing.T
类型的指针,用于报告测试结果和错误信息。
2.3 子测试和子测试函数
testify 库中的子测试和子测试函数与 testing 库中的子测试和子测试函数类似,用于对测试用例进行分组和子分组,以更好地组织和管理测试代码。子测试函数可以嵌套在其他子测试函数中,形成一个树状结构。子测试和子测试函数可以共享测试数据和测试逻辑,提高测试代码的复用性和可维护性。
以下是一个子测试函数示例:
package mainimport ("testing""github.com/stretchr/testify/suite"
)type MyTestSuite struct {suite.Suite
}func (s *MyTestSuite) TestAdd() {s.Run("normal case", func() {got := Add(2, 3)want := 5s.Equal(got, want)})s.Run("edge case", func() {got := Add(0, 0)want := 0s.Equal(got, want)})
}func TestMyTestSuite(t *testing.T) {suite.Run(t, new(MyTestSuite))
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 suite.Suite
类型来定义一个测试套件,并在测试套件中定义了一个 TestAdd
测试函数。在 TestAdd
测试函数中,我们使用了 s.Run
函数定义了两个子测试函数,分别测试了 Add
函数的正常情况和边界情况。每个子测试函数都接受一个闭包函数,用于测试具体的测试用例。在子测试函数中,我们使用了 s.Equal
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。最后,我们使用了 suite.Run
函数来运行测试套件。
2.4 示例和基准测试
testify 库中的示例和基准测试与 testing 库中的示例和基准测试类似,用于展示函数的使用方法和测试函数的性能。示例函数以 Example
开头,接受一个 *testing.T
类型的参数,用于展示函数的使用方法。基准测试函数以 Benchmark
开头,接受一个 *testing.B
类型的参数,用于测试函数的性能。
以下是一个示例函数示例:
package mainimport ("testing""github.com/stretchr/testify/assert"
)func ExampleAdd() {got := Add(2, 3)assert.Equal(t, got, 5)// Output:// 5
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 assert.Equal
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。示例函数的输出会被测试框架捕获并打印到控制台上。
以下是一个基准测试函数示例:
package mainimport ("testing""github.com/stretchr/testify/require"
)func BenchmarkAdd(b *testing.B) {for i := 0; i < b.N; i++ {require.Equal(t, Add(2, 3), 5)}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 require.Equal
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。基准测试函数会运行多次,以获取平均性能数据。
2.5 测试覆盖率分析
testify 库中的测试覆盖率分析与 testing 库中的测试覆盖率分析类似,用于评估测试用例的质量和测试代码的完整性。testify 库提供了 go test -cover
命令来进行测试覆盖率分析,该命令会输出被测试代码的覆盖率数据。
以下是一个测试覆盖率分析示例:
package mainimport ("testing""github.com/stretchr/testify/assert"
)func TestAdd(t *testing.T) {got := Add(2, 3)assert.Equal(t, got, 5)
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 assert.Equal
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。我们使用了 go test -cover
命令进行测试覆盖率分析。测试覆盖率分析结果如下:
$ go test -cover
PASS
coverage: 100.0% of statements
ok github.com/username/project 0.002s
从结果可以看出,被测试代码的覆盖率为 100%,说明测试用例的质量较好,测试代码的完整性较高。
2.6 并发测试
testify 库中的并发测试与 testing 库中的并发测试类似,用于测试并发代码的正确性和性能。testify 库提供了 t.Parallel()
函数来启用并发测试,该函数会告诉测试框架可以并发运行测试用例。
以下是一个并发测试示例:
package mainimport ("sync""testing""github.com/stretchr/testify/assert"
)func TestCounter(t *testing.T) {t.Parallel()counter := NewCounter()var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()counter.Inc()}()go func() {defer wg.Done()counter.Inc()}()wg.Wait()got := counter.Value()want := 2assert.Equal(t, got, want)
}type Counter struct {value intmutex sync.Mutex
}func NewCounter() *Counter {return &Counter{}
}func (c *Counter) Inc() {c.mutex.Lock()defer c.mutex.Unlock()c.value++
}func (c *Counter) Value() int {c.mutex.Lock()defer c.mutex.Unlock()return c.value
}
在这个示例中,我们使用了 t.Parallel()
函数启用了并发测试。我们测试了一个并发计数器的正确性,该计数器使用了 sync.Mutex
来保证线程安全。在测试函数中,我们使用了 sync.WaitGroup
来等待所有 Goroutine 运行完毕。
2.7 表格驱动测试
testify 库中的表格驱动测试与 testing 库中的表格驱动测试类似,用于对多组测试用例进行批量测试。表格驱动测试可以大大简化测试代码,提高测试代码的复用性和可维护性。
以下是一个表格驱动测试示例:
package mainimport ("testing""github.com/stretchr/testify/assert"
)func TestAdd(t *testing.T) {cases := []struct {x, y, want int}{{2, 3, 5},{0, 0, 0},{-1, 1, 0},}for _, c := range cases {got := Add(c.x, c.y)assert.Equal(t, got, c.want)}
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了表格驱动测试对 Add
函数进行了批量测试。我们定义了一个包含多组测试用例的结构体数组,每个测试用例都包含了 x
、y
和 want
三个字段。在测试函数中,我们遍历了所有的测试用例,并对每个测试用例进行了测试。
2.8 Mock测试
testify 库中的 Mock 测试与 testing 库中的 Mock 测试类似,用于模拟依赖组件的行为,以隔离被测试代码。testify 库提供了一个名为 mock
的子包,用于创建和管理模拟对象。
以下是一个 Mock 测试示例:
package mainimport ("testing""github.com/stretchr/testify/assert""github.com/stretchr/testify/mock"
)type UserService interface {GetUser(id int) (*User, error)
}type User struct {ID intName string
}type UserController struct {UserService UserService
}func (c *UserController) GetUser(id int) (*User, error) {return c.UserService.GetUser(id)
}type MockUserService struct {mock.Mock
}func (m *MockUserService) GetUser(id int) (*User, error) {args := m.Called(id)return args.Get(0).(*User), args.Error(1)
}func TestUserController_GetUser(t *testing.T) {userService := new(MockUserService)userService.On("GetUser", 1).Return(&User{ID: 1, Name: "Tom"}, nil)controller := &UserController{UserService: userService}user, err := controller.GetUser(1)assert.NoError(t, err)assert.Equal(t, user.Name, "Tom")userService.AssertExpectations(t)
}
在这个示例中,我们使用了 mock
子包来创建和管理模拟对象。我们定义了一个 UserService
接口,用于模拟用户服务的行为。我们还定义了一个 MockUserService
结构体,用于实现 UserService
接口,并使用 mock
子包来模拟 UserService
的行为。在测试函数中,我们使用了 MockUserService
来模拟用户服务的行为,并对 UserController
进行了测试。
3. ginkgo库
ginkgo 是一个用于 Go 语言的行为驱动开发(BDD)测试框架,提供了一套简单易用、功能强大、可扩展性好的测试工具,用于帮助开发者更高效地进行单元测试和集成测试。ginkgo 库的设计目标是提供一套更加自然、直观、易于理解的测试语言,以帮助开发者更好地表达测试用例的意图和期望。
3.1 基本概述
ginkgo 库是一个第三方的 Go 测试库,用于对 Go 代码进行自动化测试。ginkgo 库提供了一系列的测试工具,包括描述(Describe)、上下文(Context)、它(It)、指定(Specify)等,用于帮助开发者更好地组织和管理测试代码。
3.2 测试函数
3.2.1 命名规则
ginkgo 库中的测试函数命名规则与 testing 库中的测试函数命名规则类似,必须以 Test
开头,接受一个 *testing.T
类型的参数,并且不能有任何返回值。测试函数必须放在要测试的包的 _test.go
文件中,否则不会被测试框架识别。
3.2.2 函数签名
ginkgo 库中的测试函数的函数签名如下:
func TestName(t *testing.T)
其中,Name
是测试函数的名称,通常为要测试的函数或方法的名称。t
是一个指向 testing.T
类型的指针,用于报告测试结果和错误信息。
3.3 子测试和子测试函数
ginkgo 库中的子测试和子测试函数与 testing 库中的子测试和子测试函数类似,用于对测试用例进行分组和子分组,以更好地组织和管理测试代码。子测试函数可以嵌套在其他子测试函数中,形成一个树状结构。子测试和子测试函数可以共享测试数据和测试逻辑,提高测试代码的复用性和可维护性。
以下是一个子测试函数示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Add", func() {Context("normal case", func() {It("should return 5", func() {got := Add(2, 3)want := 5Expect(got).To(Equal(want))})})Context("edge case", func() {It("should return 0", func() {got := Add(0, 0)want := 0Expect(got).To(Equal(want))})})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 Describe
函数来定义一个测试套件,并在测试套件中定义了两个子测试函数,分别测试了 Add
函数的正常情况和边界情况。每个子测试函数都接受一个闭包函数,用于测试具体的测试用例。在子测试函数中,我们使用了 Expect
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。最后,我们使用了 RunSpecs
函数来运行测试套件。
3.4 示例和基准测试
ginkgo 库中的示例和基准测试与 testing 库中的示例和基准测试类似,用于展示函数的使用方法和测试函数的性能。示例函数以 Example
开头,接受一个 *testing.T
类型的参数,用于展示函数的使用方法。基准测试函数以 Benchmark
开头,接受一个 *testing.B
类型的参数,用于测试函数的性能。
以下是一个示例函数示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Add", func() {It("should return 5", func() {got := Add(2, 3)want := 5Expect(got).To(Equal(want))})Context("example", func() {It("should return 5", func() {got := Add(2, 3)Expect(got).To(Equal(5))// Output:// 5})})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 Expect
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。示例函数的输出会被测试框架捕获并打印到控制台上。
以下是一个基准测试函数示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Add", func() {It("should return 5", func() {got := Add(2, 3)want := 5Expect(got).To(Equal(want))})Context("benchmark", func() {It("should benchmark Add function", func() {for i := 0; i < b.N; i++ {Add(2, 3)}})})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 Expect
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。基准测试函数会运行多次,以获取平均性能数据。
3.5 测试覆盖率分析
ginkgo 库中的测试覆盖率分析与 testing 库中的测试覆盖率分析类似,用于评估测试用例的质量和测试代码的完整性。ginkgo 库提供了 go test -cover
命令来进行测试覆盖率分析,该命令会输出被测试代码的覆盖率数据。
以下是一个测试覆盖率分析示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Add", func() {It("should return 5", func() {got := Add(2, 3)want := 5Expect(got).To(Equal(want))})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 Expect
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。我们使用了 go test -cover
命令进行测试覆盖率分析。测试覆盖率分析结果如下:
$ go test -cover
PASS
coverage: 100.0% of statements
ok github.com/username/project 0.002s
从结果可以看出,被测试代码的覆盖率为 100%,说明测试用例的质量较好,测试代码的完整性较高。
3.6 并发测试
ginkgo 库中的并发测试与 testing 库中的并发测试类似,用于测试并发代码的正确性和性能。ginkgo 库提供了 JustBeforeEach
、AfterEach
和 Parallel
等函数来支持并发测试。
以下是一个并发测试示例:
package mainimport ("sync""testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var counter *Counter
var wg *sync.WaitGroupvar _ = Describe("Counter", func() {BeforeEach(func() {counter = NewCounter()wg = &sync.WaitGroup{}})AfterEach(func() {wg.Wait()})It("should increment counter", func() {wg.Add(1)go func() {counter.Inc()wg.Done()}()eventually(func() int {return counter.Value()}, "1 second").Should(Equal(1))})It("should increment counter concurrently", func() {wg.Add(2)go func() {counter.Inc()wg.Done()}()go func() {counter.Inc()wg.Done()}()eventually(func() int {return counter.Value()}, "1 second").Should(Equal(2))}, 2)
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}type Counter struct {value intmutex sync.Mutex
}func NewCounter() *Counter {return &Counter{}
}func (c *Counter) Inc() {c.mutex.Lock()defer c.mutex.Unlock()c.value++
}func (c *Counter) Value() int {c.mutex.Lock()defer c.mutex.Unlock()return c.value
}
在这个示例中,我们使用了 BeforeEach
函数来初始化计数器和等待组,使用了 AfterEach
函数来等待所有 Goroutine 运行完毕。在第一个测试用例中,我们使用了 eventually
函数来等待计数器的值为 1。在第二个测试用例中,我们使用了 Parallel
函数来启用并发测试,并使用了 eventually
函数来等待计数器的值为 2。
3.7 表格驱动测试
ginkgo 库中的表格驱动测试与 testing 库中的表格驱动测试类似,用于对多组测试用例进行批量测试。表格驱动测试可以大大简化测试代码,提高测试代码的复用性和可维护性。
以下是一个表格驱动测试示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega"
)var _ = Describe("Add", func() {It("should return correct result", func() {cases := []struct {x, y, want int}{{2, 3, 5},{0, 0, 0},{-1, 1, 0},}for _, c := range cases {got := Add(c.x, c.y)Expect(got).To(Equal(c.want))}})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了表格驱动测试对 Add
函数进行了批量测试。我们定义了一个包含多组测试用例的结构体数组,每个测试用例都包含了 x
、y
和 want
三个字段。在测试函数中,我们遍历了所有的测试用例,并对每个测试用例进行了测试。
3.8 Mock测试
ginkgo 库中的 Mock 测试与 testing 库中的 Mock 测试类似,用于模拟依赖组件的行为,以隔离被测试代码。ginkgo 库提供了一个名为 gock
的子包,用于创建和管理模拟对象。
以下是一个 Mock 测试示例:
package mainimport ("testing". "github.com/onsi/ginkgo". "github.com/onsi/gomega""github.com/stretchr/testify/mock""gopkg.in/h2non/gock.v1"
)type UserService interface {GetUser(id int) (*User, error)
}type User struct {ID intName string
}type UserController struct {UserService UserService
}func (c *UserController) GetUser(id int) (*User, error) {return c.UserService.GetUser(id)
}type MockUserService struct {mock.Mock
}func (m *MockUserService) GetUser(id int) (*User, error) {args := m.Called(id)return args.Get(0).(*User), args.Error(1)
}var _ = Describe("UserController", func() {var userService *MockUserServicevar controller *UserControllerBeforeEach(func() {userService = &MockUserService{}controller = &UserController{UserService: userService}})AfterEach(func() {gock.OffAll()})It("should return user", func() {user := &User{ID: 1, Name: "Tom"}userService.On("GetUser", 1).Return(user, nil)got, err := controller.GetUser(1)Expect(err).To(BeNil())Expect(got).To(Equal(user))})It("should return error", func() {userService.On("GetUser", 1).Return(nil, errors.New("user not found"))got, err := controller.GetUser(1)Expect(err).To(HaveOccurred())Expect(got).To(BeNil())})
})func TestMyTestSuite(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, "My Test Suite")
}
在这个示例中,我们使用了 gock
子包来创建和管理模拟对象。我们定义了一个 UserService
接口,用于模拟用户服务的行为。我们还定义了一个 MockUserService
结构体,用于实现 UserService
接口,并使用 mock
子包来模拟 UserService
的行为。在测试函数中,我们使用了 MockUserService
来模拟用户服务的行为,并对 UserController
进行了测试。
4. gocheck库
gocheck 是一个用于 Go 语言的测试库,提供了丰富的断言函数和测试套件等测试功能。gocheck 库的设计目标是提供一套简单易用、功能强大、可扩展性好的测试工具,以帮助开发者更高效地进行单元测试和集成测试。
4.1 基本概述
gocheck 库是一个第三方的 Go 测试库,用于对 Go 代码进行自动化测试。gocheck 库提供了一系列的测试工具,包括断言函数、测试套件等,用于帮助开发者更好地组织和管理测试代码。
4.2 测试函数
4.2.1 命名规则
gocheck 库中的测试函数命名规则与 testing 库中的测试函数命名规则类似,必须以 Test
开头,接受一个 *testing.T
类型的参数,并且不能有任何返回值。测试函数必须放在要测试的包的 _test.go
文件中,否则不会被测试框架识别。
4.2.2 函数签名
gocheck 库中的测试函数的函数签名如下:
func TestName(t *testing.T)
其中,Name
是测试函数的名称,通常为要测试的函数或方法的名称。t
是一个指向 testing.T
类型的指针,用于报告测试结果和错误信息。
4.3 子测试和子测试函数
gocheck 库中的子测试和子测试函数与 testing 库中的子测试和子测试函数类似,用于对测试用例进行分组和子分组,以更好地组织和管理测试代码。子测试函数可以嵌套在其他子测试函数中,形成一个树状结构。子测试和子测试函数可以共享测试数据和测试逻辑,提高测试代码的复用性和可维护性。
以下是一个子测试函数示例:
package mainimport ("testing""github.com/go-check/check"
)type MyTestSuite struct{}var _ = check.Suite(&MyTestSuite{})func (s *MyTestSuite) TestAdd(c *check.C) {c.Run("normal case", func(c *check.C) {got := Add(2, 3)want := 5c.Assert(got, check.Equals, want)})c.Run("edge case", func(c *check.C) {got := Add(0, 0)want := 0c.Assert(got, check.Equals, want)})
}func TestMyTestSuite(t *testing.T) {check.TestingT(t)
}func Add(x, y int) int {return x + y
}
在这个示例中,我们使用了 check.Suite
类型来定义一个测试套件,并在测试套件中定义了一个 TestAdd
测试函数。在 TestAdd
测试函数中,我们使用了 c.Run
函数定义了两个子测试函数,分别测试了 Add
函数的正常情况和边界情况。每个子测试函数都接受一个闭包函数,用于测试具体的测试用例。在子测试函数中,我们使用了 c.Assert
函数来比较实际值和预期值,如果两者不相等,则报告错误信息。最后,我们使用了 check.TestingT
函数来运行测试套件。
4.4 Suite和SuiteSetUp
Gocheck提供了Suite和SuiteSetUp两个概念,用于组织测试代码。Suite是一个测试套件,它包含一组相关的测试用例。SuiteSetUp是一个可选的函数,它在Suite中的所有测试用例运��之前被调用,用于执行一些初始化操作。
以下是一个使用Suite和SuiteSetUp的例子:
package main_testimport ("testing""github.com/go-check/check"
)type Suite struct {db *DB
}var _ = check.Suite(&Suite{})func (s *Suite) SetUpSuite(c *check.C) {s.db = NewDB()
}func (s *Suite) TearDownSuite(c *check.C) {s.db.Close()
}func (s *Suite) TestAdd(c *check.C) {s.db.Add("test")c.Assert(s.db.Count(), check.Equals, 1)
}func (s *Suite) TestRemove(c *check.C) {s.db.Add("test")s.db.Remove("test")c.Assert(s.db.Count(), check.Equals, 0)
}func TestSuite(t *testing.T) {check.TestingT(t)
}
在这个例子中,我们定义了一个名为Suite的结构体,它包含一个DB类型的成员变量。我们使用check.Suite
函数将Suite注册为一个测试套件。我们还定义了两个函数SetUpSuite
和TearDownSuite
,它们分别在Suite中的所有测试用例运行之前和运行之后被调用。在SetUpSuite
函数中,我们创建了一个新的DB实例,并将其赋值给Suite的db成员变量。在TearDownSuite
函数中,我们关闭了DB实例。
在Suite中,我们定义了两个测试用例TestAdd
和TestRemove
,它们分别测试了DB的Add和Remove方法。在每个测试用例中,我们使用了Suite的db成员变量来操作DB。
在测试套件中,我们使用check.TestingT
函数来运行测试套件。
4.5 跳过测试
Gocheck提供了一个名为Skip
的函数,用于跳过某些测试用例。Skip函数接收一个字符串参数,用于描述跳过测试的原因。
以下是一个使用Skip函数跳过测试用例的例子:
package main_testimport ("testing""github.com/go-check/check"
)type Suite struct{}var _ = check.Suite(&Suite{})func (s *Suite) TestSkip(c *check.C) {c.Skip("Skip this test")
}func TestSuite(t *testing.T) {check.TestingT(t)
}
在这个例子中,我们定义了一个名为TestSkip
的测试用例,它调用了c.Skip
函数来跳过这个测试用例。在控制台输出中,我们可以看到这个测试用例被跳过了:
$ go test -v
=== RUN TestSuite
=== SKIP TestSuite.TestSkip
--- PASS: TestSuite (0.00s)--- SKIP: TestSuite.TestSkip (0.00s)
PASS
ok command-line-arguments 0.011s
4.6 测试覆盖率
Go语言提供了一个名为go tool cover
的工具,用于测量测试覆盖率。测试覆盖率是指被测试代码中被测试用例执行到的代码行数占总代码行数的比例。
以下是一个测试覆盖率的例子:
$ go test -cover
PASS
coverage: 80.0% of statements
ok command-line-arguments 0.011s
在这个例子中,我们使用了-cover
标志来运行测试,并输出了测试覆盖率。在这个例子中,测试覆盖率为80%,表示被测试代码中有80%的代码行数被测试用例执行到了。
如果想要生成一个可视化的测试覆盖率报告,可以使用-coverprofile
标志来指定一个输出文件,然后使用go tool cover
命令来生成报告:
$ go test -cover -coverprofile=cover.out
$ go tool cover -html=cover.out
在这个例子中,我们使用了-coverprofile
标志来指定一个输出文件cover.out
,然后使用了go tool cover
命令来生成一个HTML格式的测试覆盖率报告。
5. gomega库
Gomega是一个Go语言的测试库,它提供了一组丰富的匹配器,用于简化测试用例的编写和维护。Gomega库是Ginkgo库的部分,但也可以单独使用。
5.1 基本概述
Gomega库提供了一组匹配器,用于简化测试用例的编写和维护。匹配器是一种特殊的函数,它接收一个实际值和一个期望值,然后返回一个布尔值,表示实际值是否满足期望值。
Gomega库还提供了一些辅助函数,用于打印测试用例的结果和错误信息。
5.2 安装
可以使用以下命令来安装Gomega库:
$ go get github.com/onsi/gomega
5.3 使用
以下是一个使用Gomega库的例子:
package main_testimport ("testing""github.com/onsi/gomega""github.com/stretchr/testify/assert"
)func TestGomega(t *testing.T) {g := gomega.NewGomegaWithT(t)// 使用Gomega的匹配器来测试一个整数num := 10g.Expect(num).To(gomega.Equal(10))g.Expect(num).NotTo(gomega.Equal(20))g.Expect(num).To(gomega.BeNumerically(">", 5))g.Expect(num).To(gomega.BeNumerically("<=", 10))// 使用Gomega的匹配器来测试一个字符串str := "hello"g.Expect(str).To(gomega.Equal("hello"))g.Expect(str).NotTo(gomega.Equal("world"))g.Expect(str).To(gomega.ContainSubstring("ell"))g.Expect(str).To(gomega.HaveLen(5))// 使用Gomega的匹配器来测试一个切片slice := []int{1, 2, 3}g.Expect(slice).To(gomega.HaveLen(3))g.Expect(slice).To(gomega.ContainElement(2))g.Expect(slice).NotTo(gomega.ContainElement(4))// 使用Testify的断言来测试一个错误err := someFunctionThatReturnsAnError()assert.NotNil(t, err)g.Expect(err).To(gomega.HaveOccurred())g.Expect(err.Error()).To(gomega.ContainSubstring("some error"))
}func someFunctionThatReturnsAnError() error {return fmt.Errorf("some error")
}
在这个例子中,我们使用了gomega.NewGomegaWithT
函数来创建一个新的Gomega实例,并将其绑定到当前的测试用例中。然后,我们使用了Gomega的匹配器来测试一个整数、一个字符串和一个切片。在测试过程中,我们使用了g.Expect
函数来检查实际值是否满足期望值。
在最后,我们使用了Testify的断言来测试一个错误,并使用了Gomega的匹配器来检查错误的信息。
在控制台输出中,我们可以看到测试用例的结果和错误信息:
$ go test -v
=== RUN TestGomega
--- PASS: TestGomega (0.00s)
PASS
ok command-line-arguments 0.012s
5.4 匹配器
Gomega库提供了许多内置的匹配器,用于测试不同类型的值。以下是一些常用的匹配器:
Equal(expected interface{})
:检查实际值是否等于期望值。Not(matcher Matcher)
:检查实际值是否不满足给定的匹配器。BeNumerically(operator string, value interface{})
:检查实际值是否满足给定的数值比较运算符和值。ContainSubstring(substring string)
:检查实际值是否包含给定的子字符串。HaveLen(length int)
:检查实际值的长度是否等于给定的长度。ContainElement(element interface{})
:检查实际值是否包含给定的元素。HaveOccurred()
:检查实际值是否为一个非nil的错误。HavePrefix(prefix string)
:检查实际值是否以给定的前缀开头。HaveSuffix(suffix string)
:检查实际值是否以给定的后缀结尾。
5.5 自定义匹配器
Gomega库允许用户定义自己的匹配器。以下是一个自定义匹配器的例子:
package main_testimport ("testing""github.com/onsi/gomega"
)func TestCustomMatcher(t *testing.T) {g := gomega.NewGomegaWithT(t)// 定义一个自定义匹配器matcher := gomega.WithTransform(func(actual interface{}) interface{} {return actual.(string) + " world"}, gomega.Equal("hello world"))// 使用自定义匹配器来测试一个字符串str := "hello"g.Expect(str).To(matcher)
}
在这个例子中,我们定义了一个名为matcher
的自定义匹配器,它使用了gomega.WithTransform
函数来转换实际值,然后使用了gomega.Equal
函数来检查转换后的值是否等于期望值。在测试过程中,我们使用了g.Expect
函数来检查实际值是否满足自定义匹配器。
在控制台输出中,我们可以看到测试用例的结果和错误信息:
$ go test -v
=== RUN TestCustomMatcher
--- PASS: TestCustomMatcher (0.00s)
PASS
ok command-line-arguments 0.012s
6. goconvey库
Goconvey是一个Go语言的测试库,它提供了一个 web 界面,用于查看测试用例的结果和错误信息。Goconvey库是Ginkgo库的一部分,但也可以单独使用。
6.1 基本概述
Goconvey库提供了一个 web 界面,用于查看测试用例的结果和错误信息。在 web 界面中,用户可以查看测试用例的执行过程、测试覆盖率、错误信息等。
Goconvey库还提供了一些辅助函数,用于打印测试用例的结果和错误信息。
6.2 安装
可以使用以下命令来安装Goconvey库:
$ go get github.com/smartystreets/goconvey/convey
6.3 使用
以下是一个使用Goconvey库的例子:
package main_testimport ("testing""github.com/smartystreets/goconvey/convey"
)func TestConvey(t *testing.T) {convey.Convey("TestConvey", t, func() {convey.Convey("Given a number", func() {num := 10convey.Convey("When the number is added by 1", func() {num++convey.Convey("Then the number should be 11", func() {convey.So(num, convey.ShouldEqual, 11)})})})})
}
在这个例子中,我们使用了convey.Convey
函数来定义一个测试用例,然后使用了convey.So
函数来检查实际值是否满足期望值。在测试过程中,我们使用了convey.Convey
函数来描述测试用例的执行过程。
在控制台输出中,我们可以看到测试用例的结果和错误信息:
$ go test -v
=== RUN TestConvey
=== RUN TestConvey/Given_a_number
=== RUN TestConvey/Given_a_number/When_the_number_is_added_by_1
=== RUN TestConvey/Given_a_number/When_the_number_is_added_by_1/Then_the_number_should_be_11
--- PASS: TestConvey (0.00s)--- PASS: TestConvey/Given_a_number (0.00s)--- PASS: TestConvey/Given_a_number/When_the_number_is_added_by_1 (0.00s)--- PASS: TestConvey/Given_a_number/When_the_number_is_added_by_1/Then_the_number_should_be_11 (0.00s)
PASS
ok command-line-arguments 0.012s
在 web 界面中,我们可以查看更详细的测试用例结果和错误信息:
$ go test -v | go-convey-web
然后,在浏览器中打开http://localhost:8080,即可查看测试用例的结果和错误信息。
6.4 辅助函数
Goconvey库提供了一些辅助函数,用于打印测试用例的结果和错误信息。以下是一些常用的辅助函数:
convey.So(actual interface{}, message string, f convey.FailFunc)
:检查实际值是否满足给定的条件,如果不满足,则调用f
函数来打印错误信息。convey.Should(actual interface{}) convey.Shoulder
:返回一个convey.Shoulder
接口,用于链式调用其他辅助函数。convey.ShouldEqual(expected interface{})
:检查实际值是否等于给定的期望值。convey.ShouldNotEqual(unexpected interface{})
:检查实际值是否不等于给定的期望值。convey.ShouldBeNil()
:检查实际值是否为nil。convey.ShouldNotBeNil()
:检查实际值是否不为nil。convey.ShouldBeTrue(b bool)
:检查实际值是否为true。convey.ShouldBeFalse(b bool)
:检查实际值是否为false。convey.ShouldResemble(expected interface{})
:检查实际值是否与给定的期望值具有相同的结构和值。convey.ShouldNotResemble(unexpected interface{})
:检查实际值是否与给定的期望值具有不同的结构或值。convey.ShouldPanic(f func())
:检查调用f
函数是否会引发panic。convey.ShouldNotPanic(f func())
:检查调用f
函数是否不会引发panic。
6.5 配置
Goconvey库提供了一些配置选项,用于自定义测试用例的执行和输出。以下是一些常用的配置选项:
convey.Coverage
:启用或禁用测试覆盖率的计算。convey.MaxDepth
:设置测试用例的最大嵌套深度。convey.Report
:设置测试用例的报告模式。convey.Trace
:设置测试用例的跟踪模式。convey.WebRoot
:设置 web 界面的根目录。convey.WebPort
:设置 web 界面的端口号。
可以在测试用例中使用convey.Configure
函数来设置这些配置选项。
总结
单元测试是保证代码质量的重要手段,Go语言提供了丰富的测试框架和工具来帮助我们编写高质量的单元测试。本文介绍了几个流行的测试框架和工具,如testing库、testify库、ginkgo库、gocheck库、gomega库和goconvey库。每个工具都有其独特的特性和用法,可以满足不同的测试需求。通过掌握这些工具,开发人员可以更好地编写和执行单元测试,提高软件质量和稳定性。
相关文章:
【Golang星辰图】构建健壮应用的秘籍:探索Go语言中最强大的测试工具库
精进单元测试:探秘Go语言中流行的测试框架和工具 前言 提高软件质量和稳定性是每个开发人员的目标之一。而单元测试是保证代码质量的重要手段之一,可以帮助我们检查代码是否按预期工作,并提早发现潜在的bug。Go语言提供了丰富的测试框架和工…...

刷题笔记day27-回溯算法3
39. 组合总和 var path []int var tmp []int var result [][]int// 还是需要去重复,题目中要求的是至少一个数字备选的数量不同。 // 所以需要剪枝操作,右边的要比左边的> func combinationSum(candidates []int, target int) [][]int {// 组合问题pa…...

【项目】Boost 搜索引擎
文章目录 1.背景2.宏观原理3.相关技术与开发环境4. 实现原理1.下载2.加载与解析文件2.1获取指定目录下的所有网页文件2.2. 获取网页文件中的关键信息2.3. 对读取文件进行保存 3.索引3.1正排与倒排3.2获取正排和倒排索引3.3建立索引3.3.1正排索引3.3.2倒排索引 4.搜索4.1 初始化…...
vue3 (六)自定义指令
1.定义自定义指令: app.directive(pos,{mounted(el,bunding){el.style[bunding.arg] bunding.value px;}, updated(el,bunding){el.style[bunding.arg] bunding.value px;} }) app.directive(指令名,{ mounted(el,bunding){}, updated(el,bunding){} }) 如果只…...
vite、mode如果为production打包后 .env.production 中 VITE_API_DOMAIN变量作为API地址吗
Vite 是一个现代化的前端构建工具,它使用 .env 文件来管理不同环境下的环境变量。通过为不同的环境(如开发环境、生产环境等)设置不同的 .env 文件,你可以控制这些环境中的变量,这些变量在构建时会被注入到项目中 当你…...

静态时序分析:SDC约束命令set_fasle_path详解
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 目录 指定建立/保持时间检查 指定上升/下降沿 指定时序路径起点 删除虚假路径 添加注释 简单使用 写在最后 在之前的文章中,我们讨论了如何使…...
浅谈马尔科夫链蒙特卡罗方法(MCMC)算法的理解
1.解决的问题 计算机怎么在任意给定的概率分布P上采样?首先可以想到把它拆成两步: (1)首先等概率的从采样区间里取一个待定样本x,并得到它的概率为p(x) (2)然后在均匀分布U[0,1]上取一个值&a…...
2403C++,C++20协程库
原文 基于C20协程的http库--cinatra cinatra是基于C20无栈协程实现的跨平台,仅头,高性能,易用的http/https库(http1.1),包括httpserver和httpclient,功能完备,不仅支持最普通的getpost等请求,还支持restfulapi,websocket,chunked,ranges,multipart,静态文件服务和反向代理等功…...
mybatis动态加载mapper.xml
mybatis动态加载mapper.xml mybatis动态加载mapper.xml、springboot mybatis动态加载mapper.xml 教程连接:https://blog.csdn.net/weixin_44480167/article/details/136356398...

安卓类加载机制
目录 一、ClassLoader介绍二、双亲委托机制三、类的加载过程 一、ClassLoader介绍 任何一个 Java 程序都是由一个或多个 class 文件组成,在程序运行时,需要将 class 文件加载到 JVM 中才可以使用,负责加载这些 class 文件的就是 Java 的类加…...

FPGA高端项目:FPGA基于GS2971的SDI视频接收+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持
目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS动态字符叠加输出应用本方案的SDI接收HLS多路视频融合叠加应用本方案…...

[计算机网络]--五种IO模型和select
前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、五种IO…...
【力扣经典面试题】14. 最长公共前缀
目录 一、题目描述 二、解题思路 三、解题步骤 四、代码实现(C版详细注释) 五、总结 欢迎点赞关注哦!创作不易,你的支持是我的不竭动力,更多精彩等你哦。 一、题目描述 编写一个函数来查找字符串数组中的最长公共前缀。…...

Linux操作系统的vim常用命令和vim 键盘图
在vi编辑器的命令模式下,命令的组成格式是:nnc。其中,字符c是命令,nn是整数值,它表示该命令将重复执行nn次,如果不给出重复次数的nn值,则命令将只执行一次。例如,在命令模式下按j键表…...

SpringCloudGateway工作原理与链路图
SpringCloudGateway基本介绍 Spring Cloud Gateway 构建于Spring Boot 2.x、 Spring WebFlux和Project Reactor之上。因此,在使用 Spring Cloud Gateway 时,您可能不会应用许多熟悉的同步库(例如 Spring Data 和 Spring Security)和模式。 Spring Cloud Gateway 需要 Sprin…...
VUE2与VUE3之间的主要区别
当谈到 Vue.js 的版本时,Vue 2 和 Vue 3 是最常被提及的两个版本。下面是 Vue 2 和 Vue 3 之间的一些主要区别: 1. 性能提升: Vue 3 在底层核心重写了响应式系统,采用了 Proxy 对象,大幅提高了性能。Vue 3 还引入了静…...

CSS浮动实战,经典好文
零基础学web前端开发要怎么去学? 首先要学习的就是基础知识:html、css和JavaScript。HTML是内容,CSS是表现,JavaScript是行为。前端开发的门槛其实非常低,与服务器端语言先慢后快的学习曲线相比,前端开发的学习曲线是…...

如何搭建Nacos集群
1.搭建Nacos集群 众所周知,在实际的工作中,Nacos的生成环境下一定要部署为集群状态 其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 我们计划的集群结构: 我就直接在本机上开三个Nacos来搭…...

未来已来!AI大模型引领科技革命
未来已来!AI大模型正以惊人的速度引领着科技革命。随着科技的发展,人工智能在各个领域展现出了非凡的能力和潜力,大模型更是成为了科技领域的明星。从自然语言处理到图像识别,从智能推荐到语音识别,大模型的应用正在改…...

VBA如何记录单元格中字符内容和格式
实例需求:Excel单元格中的字符可以设置不同的字体格式(大小、颜色等),有时需要将这些信息保存起来,以便于后续代码的处理(例如替换后恢复原字体颜色,或者统计某种指定格式字符个数等等ÿ…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...