Maison >développement back-end >Golang >Comment utiliser l'injection de dépendances pour les tests unitaires dans Golang ?

Comment utiliser l'injection de dépendances pour les tests unitaires dans Golang ?

WBOY
WBOYoriginal
2024-06-02 20:41:00808parcourir

L'utilisation de l'injection de dépendances (DI) dans les tests unitaires Golang peut isoler le code à tester et simplifier la configuration et la maintenance des tests. Les bibliothèques DI populaires incluent wire et go-inject, qui peuvent générer des stubs de dépendance ou des simulations pour les tests. Les étapes des tests DI comprennent la configuration des dépendances, la configuration des cas de test et la validation des résultats. Un exemple d'utilisation de DI pour tester une fonction de gestion des requêtes HTTP montre à quel point il est facile d'isoler et de tester du code sans dépendances ni communication réelles.

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

Comment utiliser l'injection de dépendances pour les tests unitaires dans Golang

L'injection de dépendances (DI) est un modèle de conception qui vous permet de fournir à un objet ses dépendances sans les créer explicitement. Dans les tests unitaires, DI peut vous aider à isoler le code que vous souhaitez tester et à faciliter la configuration et la maintenance des tests.

DI à Golang

Il existe de nombreuses bibliothèques DI populaires à Golang, dont les plus célèbres sont [wire](https://github.com/google/wire) et [go-inject](https:/ /github.com/go-inject/go-inject). Ces bibliothèques fonctionnent en générant des stubs ou des mocks qui peuvent être utilisés comme dépendances dans les tests.

Configurer les tests DI

Voici comment configurer les tests unitaires DI à l'aide de wire :

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)
            }
        })
    }
}

Utiliser DI pour les tests

Dans le test ci-dessus, nous utilisons wire.Build pour générer Une instance d'une structure Fields qui contient les stubs de dépendance à utiliser pour les tests. Nous pouvons ensuite configurer le scénario de test et affirmer les résultats comme d'habitude. 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

🎜Cas pratique🎜🎜🎜Voici comment utiliser DI pour tester unitairement une fonction qui gère les requêtes HTTP : 🎜rrreee🎜En utilisant DI et les stubs, nous pouvons facilement isoler et tester la fonction GetUser sans avoir à le faire. Implique une base de données réelle ou des requêtes HTTP. 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn