1

I am new to Golang. I am trying to write unit tests for a service file. I am using testify and it's packages testify/mock and testify/assert. Looking at different articles indicates that the MockCommentRepository written below is correct. But, one of my test fails with following message

--- FAIL: TestCommentServiceCreateForCreated (0.00s)
panic: 

mock: Unexpected Method Call
-----------------------------

Create(*domains.Comment)
                0: &domains.Comment{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Comment", Content:"Test Content", PostID:0x7b, Post:domains.Post{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x0, Title:"", Content:"", Published:false}}

The closest call I have is: 

Create(*domains.Comment)
                0: &domains.Comment{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Comment", Content:"Test Content", PostID:0x7b, Post:domains.Post{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, ID:0x7b, Title:"Test Post", Content:"Test Content", Published:true}}

Difference found in argument 0:

--- Expected
+++ Actual
@@ -24,6 +24,6 @@
   },
-  ID: (uint) 123,
-  Title: (string) (len=9) "Test Post",
-  Content: (string) (len=12) "Test Content",
-  Published: (bool) true
+  ID: (uint) 0,
+  Title: (string) "",
+  Content: (string) "",
+  Published: (bool) false
  }

Diff: 0: FAIL:  (*domains.Comment=&{{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Comment Test Content 123 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 0   false}}) != (*domains.Comment=&{{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Comment Test Content 123 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 123 Test Post Test Content true}}) [recovered]

This is the service file I want to test.

type CommentService struct {
    commentRepo domains.CommentRepositoryInterface
}

func NewCommentService(commentRepo domains.CommentRepositoryInterface) *CommentService {
    return &CommentService{
        commentRepo: commentRepo,
    }
}

func (s *CommentService) Create(request *dtos.CreateCommentRequest) (*dtos.CreateCommentResponse, error) {
    post, err := s.commentRepo.FindPostByID(request.PostID)
    if err != nil {
        return nil, fmt.Errorf("failed to find post: %w", err)
    }

    if !post.Published {
        return nil, fmt.Errorf("post is not published")
    }

    comment := &domains.Comment{
        ID:      123,
        Title:   request.Title,
        Content: request.Content,
        PostID:  request.PostID,
    }

    if err := s.commentRepo.Create(comment); err != nil {
        return nil, fmt.Errorf("failed to create comment: %w", err)
    }

    response := &dtos.CreateCommentResponse{
        ID:      comment.ID,
        Message: "Comment created successfully",
    }

    return response, nil
}

This is a mock of the CommentRepository

package mocks

import (
    "post_comment/domains"

    "github.com/stretchr/testify/mock"
)

type MockCommentRepository struct {
    mock.Mock
}

func (m *MockCommentRepository) Create(comment *domains.Comment) error {
    args := m.Called(comment)

    if args.Get(0) == nil {
        return nil
    }

    return args.Error(0)
}

func (m *MockCommentRepository) FindPostByID(postID uint) (*domains.Post, error) {
    args := m.Called(postID)

    if args.Get(0) == nil {
        return nil, args.Error(1)
    }

    return args.Get(0).(*domains.Post), args.Error(1)
}

These are the tests for CommentService.

// comment_service_test.go
func (s *CommentService) Create(request *dtos.Create) (*dtos.CreateCommentResponse, error) {
    post, err := s.commentRepo.FindPostByID(request.PostID)
    if err != nil {
        return nil, fmt.Errorf("failed to find post: %w", err)
    }

    if !post.Published {
        return nil, fmt.Errorf("post is not published")
    }

    comment := &domains.Comment{
        ID:      123,
        Title:   request.Title,
        Content: request.Content,
        PostID:  request.PostID,
    }

    if err := s.commentRepo.Create(comment); err != nil {
        return nil, fmt.Errorf("failed to update comment: %w", err)
    }

    response := &dtos.CreateCommentResponse{
        ID:      comment.ID,
        Message: "Comment updated successfully",
    }

    return response, nil
}

// No problem here
func TestCommentCreateFailsWhenPostIsNotPublished(t *testing.T) {
    // create a mock of CommentRepository
    mockRepo := new(mocks.MockCommentRepository)

    // Create a mock post
    mockPost := &domains.Post{
        Title:     "Test Post",
        Content:   "Test Content",
        Published: false,
    }

    var postId uint
    postId = 123

    // mockRepo.On("FindPostByID", postId).Return(mockPost, nil)
    mockRepo.On("FindPostByID", postId).Return(mockPost, nil)

    // create new comment service
    service := services.NewCommentService(mockRepo)

    // Create a valid request
    request := &dtos.CreateCommentRequest{
        Title:   "Test Comment",
        Content: "Test Content",
        PostID:  postId,
    }

    comment, err := service.Create(request)

    // Assert that no error occurred
    assert.Error(t, err)
    assert.EqualError(t, err, "post is not published")
    assert.Nil(t, comment)
}

// This tests is failing
func TestCreatesCommentSuccessfully(t *testing.T) {
    // create a mock of CommentRepository
    mockRepo := new(mocks.MockCommentRepository)

    var postId uint
    postId = 123

    // Create a mock post
    mockPost := &domains.Post{
        ID:        postId,
        Title:     "Test Post",
        Content:   "Test Content",
        Published: true,
    }
    // mockRepo.On("FindPostByID", postId).Return(mockPost, nil)
    mockRepo.On("FindPostByID", postId).Return(mockPost, nil).Once()

    // create new comment service
    service := services.NewCommentService(mockRepo)

    // Create a valid request
    request := &dtos.CreateCommentRequest{
        Title:   "Test Comment",
        Content: "Test Content",
        PostID:  postId,
    }

    mockComment := &domains.Comment{
        ID:      123,
        Title:   request.Title,
        Content: request.Content,
        PostID:  postId,
        Post:    *mockPost,
    }

    mockRepo.On("Create", mockComment).Return(nil).Once()

    response, err := service.Create(request)

    // Assert that no error occurred
    assert.NoError(t, err)

    // // Assert the response values
    assert.NotNil(t, response)
    assert.NotNil(t, response.ID)
    assert.Equal(t, "Comment created successfully", response.Message)

    mockRepo.AssertExpectations(t)
}

I am not sure what went wrong in the code. Can someone please guide me on resolving this issue? Thank you in advance

IamGhale
  • 1,275
  • 2
  • 14
  • 26

0 Answers0