首页 >后端开发 >Golang >如何在 Golang 中使用依赖注入进行单元测试?

如何在 Golang 中使用依赖注入进行单元测试?

WBOY
WBOY原创
2024-06-02 20:41:00806浏览

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

如何在 Golang 中使用依赖注入进行单元测试?

如何在 Golang 中使用依赖注入进行单元测试

依赖注入(DI)是一种设计模式,它允许你向对象提供其依赖项,而无需显式地创建它们。在单元测试中,DI 可以帮助你隔离要测试的代码,并使测试更容易设置和维护。

Golang 中的 DI

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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn