ホームページ >バックエンド開発 >Golang >Golang の単体テストに依存関係注入を使用するにはどうすればよいですか?

Golang の単体テストに依存関係注入を使用するにはどうすればよいですか?

WBOY
WBOYオリジナル
2024-06-02 20:41:00808ブラウズ

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 構造のインスタンス。その後、テスト ケースを設定し、通常どおり結果をアサートします。 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

🎜実践例🎜🎜🎜DI を使用して HTTP リクエストを処理する関数を単体テストする方法を次に示します: 🎜rrreee🎜 DI とスタブを使用することで、GetUser 関数を簡単に分離してテストできます。実際のデータベースや HTTP リクエストを必要とせずに済みます。 🎜

以上がGolang の単体テストに依存関係注入を使用するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。