How to Unit Test GraphQL Resolvers in Go with Testify and gqlgen/client?

Patricia Arquette
Release: 2024-10-28 05:00:01
Original
560 people have browsed it

How to Unit Test GraphQL Resolvers in Go with Testify and gqlgen/client?

Unit Testing GraphQL in Go using testify

In GraphQL schema, the Query struct defines operations that trigger the retrieval of data and the Mutation struct defines operations that modify the state. When testing you'll need to mock the objects that perform the actual CRUD operations and assert that the expected calls are made.

For the following example, we'll be using the testify and gqlgen/client packages:

graph/schema.graphql

type Query {
  user(loginname: String!): UserDetail
}

type Mutation {
  validateAccessToken(accesstoken: String!): UserEntity
}

type User { 
  loginname: String 
  avatarUrl: String 
}

type UserEntity {
  id: ID!
  loginname: String 
  avatarUrl: String
}

type UserDetail { 
  loginname: String
  avatarUrl: String
  githubUsername: String
  createAt: String
  score: Int
}
Copy after login

graph/resolver/resolver.go

<code class="go">package resolver

import (
    "github.com/mrdulin/gqlgen-cnode/services"
)

type Resolver struct {
    UserService    services.UserService
}</code>
Copy after login

services/user.go

<code class="go">package services

type UserService interface {
    GetUserByLoginname(loginname string) *model.UserDetail
    ValidateAccessToken(accesstoken string) *model.UserEntity
}</code>
Copy after login

graph/resolver/root.resolver.go

<code class="go">package resolver

import (
    "context"

    "github.com/mrdulin/gqlgen-cnode/graph/generated"
    "github.com/mrdulin/gqlgen-cnode/graph/model"
)

func (r *mutationResolver) ValidateAccessToken(ctx context.Context, accesstoken string) (*model.UserEntity, error) {
    return r.UserService.ValidateAccessToken(accesstoken), nil
}

func (r *queryResolver) User(ctx context.Context, loginname string) (*model.UserDetail, error) {
    return r.UserService.GetUserByLoginname(loginname), nil
}

// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &amp;mutationResolver{r} }

// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &amp;queryResolver{r} }

type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }</code>
Copy after login

To simulate the GraphQL requests and responses, we can create mock objects for the services:

mocks/userService.go

<code class="go">package mocks

import (
    "github.com/mrdulin/gqlgen-cnode/graph/model"
    "github.com/stretchr/testify/mock"
)

type MockedUserService struct {
    mock.Mock
}

func (s *MockedUserService) GetUserByLoginname(loginname string) *model.UserDetail {
    args := s.Called(loginname)
    return args.Get(0).(*model.UserDetail)
}

func (s *MockedUserService) ValidateAccessToken(accesstoken string) *model.UserEntity {
    args := s.Called(accesstoken)
    return args.Get(0).(*model.UserEntity)
}</code>
Copy after login

Finally, in our test file, we can import these mocks and use them to test our GraphQL resolvers:

graph/resolver/root.resolver_test.go

<code class="go">package resolver_test

import (
    "testing"

    "github.com/99designs/gqlgen/client"
    "github.com/99designs/gqlgen/graphql/handler"
    "github.com/mrdulin/gqlgen-cnode/graph/generated"
    "github.com/mrdulin/gqlgen-cnode/graph/model"
    "github.com/mrdulin/gqlgen-cnode/graph/resolver"
    "github.com/mrdulin/gqlgen-cnode/mocks"
    "github.com/stretchr/testify/mock"
    "github.com/stretchr/testify/require"
)

var (
    loginname = "mrdulin"
    avatarURL = "avatar.jpg"
    score     = 50
    createAt  = "1900-01-01"
)

func TestMutationResolver_ValidateAccessToken(t *testing.T) {

    t.Run("should validate accesstoken correctly", func(t *testing.T) {
        testUserService := new(mocks.MockedUserService)
        resolvers := resolver.Resolver{UserService: testUserService}
        c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &amp;resolvers})))
        ue := model.UserEntity{ID: "123", User: model.User{Loginname: &amp;loginname, AvatarURL: &amp;avatarURL}}
        testUserService.On("ValidateAccessToken", mock.AnythingOfType("string")).Return(&amp;ue)
        var resp struct {
            ValidateAccessToken struct{ ID, Loginname, AvatarUrl string }
        }
        q := `
      mutation { 
        validateAccessToken(accesstoken: "abc") { 
          id, 
          loginname, 
          avatarUrl 
        } 
      }
    `
        c.MustPost(q, &amp;resp)
        testUserService.AssertExpectations(t)
        require.Equal(t, "123", resp.ValidateAccessToken.ID)
        require.Equal(t, "mrdulin", resp.ValidateAccessToken.Loginname)
        require.Equal(t, "avatar.jpg", resp.ValidateAccessToken.AvatarUrl)
    })

}

func TestQueryResolver_User(t *testing.T) {
    t.Run("should query user correctly", func(t *testing.T) {
        testUserService := new(mocks.MockedUserService)
        resolvers := resolver.Resolver{UserService: testUserService}
        c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &amp;resolvers})))
        u := model.UserDetail{User: model.User{Loginname: &amp;loginname, AvatarURL: &amp;avatarURL}, Score: &amp;score, CreateAt: &amp;createAt}
        testUserService.On("GetUserByLoginname", mock.AnythingOfType("string")).Return(&amp;u)
        var resp struct {
            User struct {
                Loginname, AvatarURL, CreateAt string
                Score                          int
            }
        }
        q := `
      query GetUser($loginname: String!) { 
        user(loginname: $loginname) { 
          loginname
          avatarUrl 
          createAt 
          score 
        } 
      }
    `
        c.MustPost(q, &amp;resp, client.Var("loginname", "mrdulin"))
        testUserService.AssertCalled(t, "GetUserByLoginname", "mrdulin")
        require.Equal(t, "mrdulin", resp.User.Loginname)
        require.Equal(t, "avatar.jpg", resp.User.AvatarURL)
        require.Equal(t, 50, resp.User.Score)
        require.Equal(t, "1900-01-01", resp.User.CreateAt)
    })
}</code>
Copy after login

This test will make sure that the correct calls are made to the service methods, and that the responses are formatted as expected. The test coverage report should show full coverage of the resolver functions.

The above is the detailed content of How to Unit Test GraphQL Resolvers in Go with Testify and gqlgen/client?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!