GOLANG TESTING WITH STRETCHR/TESTIFY AND MOCKERY
Let's go through a comprehensive example that covers common features of the stretchr/testify library and mockery for mocking in Golang. This example will include testing with assertions, using the require package for strict assertions, testing HTTP handlers, and mocking dependencies using mockery.
Scenario
Imagine we have a service that fetches user information from an external API. We want to test:
- The service's functionality.
- Its integration with an external client.
- Mocking the external client.
Project Structure
/project
│
├── main.go
├── service.go
├── service_test.go
├── user_client.go
├── mocks/
│   └── UserClient.go (generated by mockery)
└── go.mod
Code Overview
- 
user_client.go
 This file defines an interface for interacting with an external user API.package project type User struct { ID int Name string } type UserClient interface { GetUserByID(id int) (*User, error) }
- 
service.go
 This file contains a service that uses the UserClient to fetch user details.package project import "fmt" type UserService struct { client UserClient } func NewUserService(client UserClient) *UserService { return &UserService{client: client} } func (s *UserService) GetUserDetails(id int) (string, error) { user, err := s.client.GetUserByID(id) if err != nil { return "", fmt.Errorf("failed to get user: %w", err) } return fmt.Sprintf("User: %s (ID: %d)", user.Name, user.ID), nil }
- 
Generating Mocks with mockery
 You can generate mocks for theUserClientusingmockery:mockery --name=UserClient --output=./mocksThis will generate a mock in mocks/UserClient.go.
- 
service_test.go
 Now, let's write a test for theUserServiceusingtestifyassertions and themockery-generatedmock.package project_test import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/mock" "project" "project/mocks" ) func TestUserService_GetUserDetails_Success(t *testing.T) { // Create a new mock client mockClient := new(mocks.UserClient) // Define what the mock should return when `GetUserByID` is called mockClient.On("GetUserByID", 1).Return(&project.User{ ID: 1, Name: "John Doe", }, nil) // Create the UserService with the mock client service := project.NewUserService(mockClient) // Test the GetUserDetails method result, err := service.GetUserDetails(1) // Use `require` for error checks require.NoError(t, err) require.NotEmpty(t, result) // Use `assert` for value checks assert.Equal(t, "User: John Doe (ID: 1)", result) // Ensure that the `GetUserByID` method was called exactly once mockClient.AssertExpectations(t) } func TestUserService_GetUserDetails_Error(t *testing.T) { // Create a new mock client mockClient := new(mocks.UserClient) // Define what the mock should return when `GetUserByID` is called with an error mockClient.On("GetUserByID", 2).Return(nil, errors.New("user not found")) // Create the UserService with the mock client service := project.NewUserService(mockClient) // Test the GetUserDetails method result, err := service.GetUserDetails(2) // Use `require` for error checks require.Error(t, err) assert.Contains(t, err.Error(), "user not found") // Ensure that the result is empty assert.Empty(t, result) // Ensure that the `GetUserByID` method was called exactly once mockClient.AssertExpectations(t) }
Key Points of This Example
- Assertions with testify:
- assertand- requirepackages are used for different types of checks.- requireis used for checks that should fail the test immediately if they fail (e.g., checking for- nilerrors).
- assertis used for checks that can continue even if they fail (e.g., comparing values).
 
- Mocking with mockery:
- mockerygenerates a mock of the- UserClientinterface.- In the test, the mock is configured with.On()to specify expected inputs and.Return()to specify the outputs.
- AssertExpectationsverifies that the mocked method was called with the expected inputs.
 
- In the test, the mock is configured with
- Testing Error Handling:
- One test checks the successful scenario, while the other tests how the service handles an error from the UserClient.
This setup covers the basic functionality of stretchr/testify for assertions and mocking with mockery, providing a structured and maintainable approach to unit testing in Golang.
If you found this helpful, let me know by leaving a 👍 or a comment!, or if you think this post could help someone, feel free to share it! Thank you very much! 😃
All rights reserved
 
  
 