在 golang 单元测试中使用依赖注入(di)可以隔离要测试的代码,简化测试设置和维护。流行的 di 库包括 wire 和 go-inject,它们可以生成依赖项桩或模拟,供测试使用。di 测试的步骤包括设置依赖项、设置测试用例和断言结果。使用 di 测试 http 请求处理函数的示例表明,它可以轻松隔离和测试代码,无需实际依赖项或通信。

如何在 Golang 中使用依赖注入进行单元测试
依赖注入(DI)是一种设计模式,它允许你向对象提供其依赖项,而无需显式地创建它们。在单元测试中,DI 可以帮助你隔离要测试的代码,并使测试更容易设置和维护。
Golang 中的 DI
立即学习“go语言免费学习笔记(深入)”;
Golang 中有许多流行的 DI 库,其中最著名的是 [wire](https://github.com/google/wire) 和 [go-inject](https://github.com/go-inject/go-inject)。这些库的工作原理是生成可以用作测试中依赖项的桩或模拟。
设置 DI 测试
以下是如何使用 wire 设置 DI 单元测试:
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
)
// Interface we want to test.
type Greeter interface {
Greet(ctx context.Context, name string) (string, error)
}
// Implementation we want to test.
type DefaultGreeter struct{}
func (g DefaultGreeter) Greet(ctx context.Context, name string) (string, error) {
return "Hello, " + name, nil
}
func TestGreeter_Greet(t *testing.T) {
type Fields struct {
greeter Greeter
}
wire.Build(Fields{
greeter: (*DefaultGreeter)(nil),
})
cases := []struct {
setup func(t *testing.T, fields Fields)
expected *string
wantErr bool
}{
{
expected: String("Hello, Bob"),
},
}
for _, tc := range cases {
tc := tc // capture range variable
t.Run(testName, func(t *testing.T) {
t.Parallel()
fields := Fields{}
tc.setup(t, fields)
result, err := fields.greeter.Greet(context.Background(), "Bob")
if (err != nil) != tc.wantErr {
t.Fatalf("error = %v, wantErr = %v", err, tc.wantErr)
}
if tc.wantErr {
return
}
if diff := cmp.Diff(*tc.expected, result); diff != "" {
t.Fatalf("result mismatch (-want +got):\n%s", diff)
}
})
}
}使用 DI 进行测试
在上面的测试中,我们使用 wire.Build 来生成一个 Fields 结构的实例,该实例包含要用于测试的依赖项桩。然后,我们可以像往常一样设置测试用例并断言结果。
实战案例
以下是如何使用 DI 单元测试一个处理 HTTP 请求的函数:
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"mypkg/handlers"
)
// Interface we want to test.
type UserService interface {
GetUser(id int) (*User, error)
}
// Implementation we want to test.
type DefaultUserService struct{}
func (s DefaultUserService) GetUser(id int) (*User, error) {
return &User{ID: id, Name: "Bob"}, nil
}
type Request struct {
UserService UserService
}
func (r Request) ServeHTTP(w http.ResponseWriter, req *http.Request) {
id, err := strconv.Atoi(mux.Vars(req)["id"])
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user, err := r.UserService.GetUser(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "%s", user.Name)
}
func TestHandler_GetUser(t *testing.T) {
r := &Request{}
type Fields struct {
userService UserService
}
wire.Build(Fields{
userService: (*DefaultUserService)(nil),
})
cases := []struct {
name string
id int
body string
want string
}{
{
body: `{"body":""}`,
want: `Bob`,
},
{
id: 2,
body: `{"body":""}`,
want: `Bob`,
},
}
for _, tc := range cases {
tc := tc // capture range variable
t.Run(tc.name, func(t *testing.T) {
req, _ := http.NewRequest("GET", "/", bytes.NewBuffer([]byte(tc.body)))
if tc.id != 0 {
req = mux.SetURLVars(req, map[string]string{"id": strconv.Itoa(tc.id)})
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(r.ServeHTTP)
handler.ServeHTTP(rr, req)
assert.Equal(t, tc.want, rr.Body.String())
})
}
}通过使用 DI 和桩,我们能够轻松地隔离和测试 GetUser 函数,而无需涉及实际的数据库或 HTTP 请求。
以上就是如何在 Golang 中使用依赖注入进行单元测试?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号