Maison  >  Article  >  développement back-end  >  Allez vous moquer

Allez vous moquer

WBOY
WBOYoriginal
2024-07-31 09:16:32610parcourir

Go mock

Qu'est-ce que Go mock

Go mock est un framework moqueur qui permet aux développeurs de créer des structures simulées pour nos interfaces et de définir leur comportement.

Par exemple, cela peut nous aider à générer les implémentations fictives pour Reponsitory et à définir le résultat attendu en fonction de certaines entrées.

Dépôt original : https://github.com/golang/mock

Maintenant, il n'est plus maintenu, nous devrions donc utiliser https://github.com/uber-go/mock à la place.

Installation

go install go.uber.org/mock/mockgen@latest

Principales caractéristiques

  • Mock Generation : gomock inclut un outil appelé mockgen qui génère automatiquement des implémentations simulées d'interfaces.
  • Attentes flexibles : Avec gomock, vous pouvez définir des attentes précises sur le comportement des objets fictifs, telles que :
    • Les arguments qu'il doit recevoir
    • Et les valeurs qu'il doit renvoyer
    • Nombre spécifique de fois, nombre minimum ou maximum de fois qu'une méthode doit être appelée

Commande Mockgen

Suivez ce document pour comprendre comment utiliser mockgen CLI :

https://github.com/uber-go/mock?tab=readme-ov-file#running-mockgen

Usage

Supposons que vous ayez une interface IUserRepo avec quelques méthodes :

ports.go

package user

type IUserRepo interface {
    GetUserByID(id int) (*User, error)
    Insert(user User) error
    Update(id int, user User) error
}

domain.go

package user

type User struct {
    ID   int
    Name string
}

service.go

package user

import "fmt"

type UserService struct {
    repo IUserRepo
}

var invalidUserIDError = fmt.Errorf("invalid user id")

func (u *UserService) Upsert(user User) error {
    if user.ID <= 0 {
        return invalidUserIDError
    }
    existingUser, err := u.repo.GetUserByID(user.ID)
    if err != nil {
        return err
    }
    if existingUser == nil {
        return u.repo.Insert(user)
    }

    return u.repo.Update(user.ID, user)
}

1. Exécutez mockgen pour générer une instance fictive

go run go.uber.org/mock/mockgen@latest -source=interface.go -destination=mock.go -package=user
  • source : Spécifie le fichier contenant l'interface du référentiel.
  • destination : Spécifie le fichier dans lequel le code fictif généré sera écrit.
  • package : Spécifie le nom du package pour la maquette générée.

2. Préciser les attentes

service_test.go

package user

import (
    "go.uber.org/mock/gomock"
    "github.com/stretchr/testify/assert"
    "testing"
)

func TestUpsertUser(t *testing.T) {
    mockCtl := gomock.NewController(t)
    defer mockCtl.Finish()

    tests := []struct {
        name                 string
        user                 User
        specifyFunctionCalls func(mock *MockIUserRepo)
        expectedError        error
    }{
        {
            user: User{ID: 1, Name: "User 1"},
            name: "Should insert",
            specifyFunctionCalls: func(mockRepo *MockIUserRepo) {
                mockRepo.EXPECT().GetUserByID(1).Return(nil, nil).Times(1)
                mockRepo.EXPECT().Insert(User{ID: 1, Name: "User 1"}).Return(nil).Times(1)
            },
        },
        {
            name: "User existed - Should update",
            user: User{ID: 1, Name: "New User Name"},
            specifyFunctionCalls: func(mockRepo *MockIUserRepo) {
                mockRepo.EXPECT().GetUserByID(1).Return(&User{ID: 1, Name: "User 1"}, nil).Times(1)
                mockRepo.EXPECT().Update(1, User{ID: 1, Name: "New User Name"}).Return(nil).Times(1)
            },
        },
        {
            expectedError: invalidUserIDError,
        },
    }

    for _, test := range tests {
        t.Run(test.name, func(t *testing.T) {
            mockRepo := NewMockIUserRepo(mockCtl)
            if test.specifyFunctionCalls != nil {
                test.specifyFunctionCalls(mockRepo)
            }
            userService := UserService{repo: mockRepo}
            err := userService.Upsert(test.user)
            assert.Equal(t, test.expectedError, err)
        })
    }
}

Dans le fichier de test ci-dessus :

  • specifyFunctionCalls nous permet de personnaliser les attentes des fonctions fictives, quelles fonctions doivent être appelées et combien de fois ces fonctions doivent être appelées.
  • Si vous essayez d'ajouter une fonction redondante dans la spécification specifieFunctionCalls (par exemple en ajoutant mockRepo.EXPECT().Update(....) dans le premier test), votre test échouera en raison de l'erreur : appel(s) manquant(s) .
  • Si votre service appelle une fonction qui n'a pas été spécifiée, votre test échouera à cause de l'erreur : il n'y a aucun appel attendu de la méthode "Insérer" pour ce récepteur.

Code source

https://github.com/huantt/gomock-demo

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
Article précédent:Test unitaire en déplacementArticle suivant:Test unitaire en déplacement