Table of Contents
Question content
Solution
repo/repo.go
services/service.go
services/service_test.go
Home Backend Development Golang Assertion: Mock: I don't know what to return because the method call was unexpected Error while writing unit test in Go

Assertion: Mock: I don't know what to return because the method call was unexpected Error while writing unit test in Go

Feb 10, 2024 am 09:00 AM
go language

断言:模拟:我不知道要返回什么,因为方法调用是意外的 在 Go 中编写单元测试时出错

In this article, php editor Xiaoxin will introduce you to a common error that occurs when writing unit tests in the Go language, that is, assertion errors. When we write unit tests, we sometimes encounter situations where the return value cannot be determined, which can lead to unexpected method call errors. In this article, we will discuss the causes and solutions to this problem to help you better handle assertion errors and ensure the accuracy and reliability of your unit tests.

Question content

I use testify in go to write unit tests for my service methods. All methods work fine except the update method, because during the update In the method, I call another method of the same service ("getbyid") in the update method.

Implement the update method in my service:

func (ts *teamservice) update(team *team.team) apperror {
    t, err := ts.teamrepo.getbyid(team.id)
    if err != nil {
        return err
    }
    if t.teamownerid != team.teamownerid {
        return newforbiddenerror(forbiddenerr)
    }

    return ts.teamrepo.update(team)
}
Copy after login

mockrepo update method:

func (t *teamrepomock) update(team *team.team) apperror {
    args := t.called(team)
    if args.error(0) != nil {
        return newnotfounderror(args.error(0))
    }

    return nil
}
Copy after login

Test implementation:

func testupdate(t *testing.t) {
    _, teamidgen, playeridgen := setupconfig()

    t.run("update a team", func(t *testing.t) {
        teamrepo, _, ts := setupteamservice(teamidgen, playeridgen)

        teamrepo.on("update", testteam1).return(nil)
        result := ts.update(testteam1)

        assert.nil(t, result)
    })

    t.run("update a team fails", func(t *testing.t) {
        teamrepo, _, ts := setupteamservice(teamidgen, playeridgen)

        expected := oopserr
        teamrepo.on("update", testteam1).return(expected)
        result := ts.update(testteam1)

        assert.equalvalues(t, expected.error(), result.error())
    })
}
Copy after login

Now when I run the test I get the following error:

--- FAIL: TestUpdate (0.01s)
    --- FAIL: TestUpdate/Update_a_team (0.01s)
panic: 
assert: mock: I don't know what to return because the method call was unexpected.
    Either do Mock.On("GetByID").Return(...) first, or remove the GetByID() call.
    This method was unexpected:
        GetByID(string)
        0: ""
    at: [/home/waleem/Desktop/project/eazykhel_server/services/teamservice/team_service_init_test.go:18 /home/waleem/Desktop/project/eazykhel_server/services/teamservice/team_service.go:146 /home/waleem/Desktop/project/eazykhel_server/services/teamservice/team_service_test.go:277] [recovered]
    panic:
Copy after login

I tried calling .on("update") before and after calling mock.on("getbyid") in the test function implementation but it doesn't work and I also modified the mockrepo update function but it didn't work.

Solution

Let me try to help you solve your problem. I copied the repository with some simplifications just to post the relevant code. If I'm not wrong in your solution, there is a service (teamservice) that calls some methods provided by the underlying package (teamrepo). You want to test the update method of the teamservice structure. After reviewing, let me show the code first and then I will try to explain each file:

repo/repo.go

package repo

type team struct {
    id          int
    teamownerid int
    name        string
}

type teamrepo struct{}

func (t *teamrepo) getbyid(id int) (team, error) {
    return team{id: id, teamownerid: id, name: "myteam"}, nil
}

func (t *teamrepo) update(team team) error {
    return nil
}
Copy after login

In this file we can find the method to simulate. The methods are: getbyid and update. Obviously this isn't your actual code, but that doesn't matter right now.

services/service.go

package services

import (
    "errors"

    "testifymock/repo"
)

type teamservice struct {
    tr teamrepointerface
}

func newteamservice(repo teamrepointerface) *teamservice {
    return &teamservice{
        tr: repo,
    }
}

type teamrepointerface interface {
    getbyid(id int) (repo.team, error)
    update(team repo.team) error
}

func (ts *teamservice) update(team *repo.team) error {
    t, err := ts.tr.getbyid(team.id)
    if err != nil {
        return err
    }

    if t.teamownerid != team.teamownerid {
        return errors.new("forbidden")
    }

    return ts.tr.update(*team)
}
Copy after login

Here we can see in the test code the service that will become our system under test (sut). With dependency injection, we will take advantage of the functionality provided by the repo package injected through the interface teamrepointerface.

services/service_test.go

package services

import (
    "errors"
    "testing"

    "testifymock/repo"

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

// 1. declare the mock struct
type teamRepoMock struct {
    mock.Mock
}

// 2. implement the interface
func (m *teamRepoMock) GetByID(id int) (repo.Team, error) {
    args := m.Called(id)

    return args.Get(0).(repo.Team), args.Error(1)
}

func (m *teamRepoMock) Update(team repo.Team) error {
    args := m.Called(team)

    return args.Error(0)
}

func TestUpdate(t *testing.T) {
    t.Run("GoodUpdate", func(t *testing.T) {
        // 3. instantiate/setup mock
        repoMock := new(teamRepoMock)
        repoMock.On("GetByID", 1).Return(repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"}, nil).Times(1)
        repoMock.On("Update", repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"}).Return(nil).Times(1)

        sut := NewTeamService(repoMock)
        err := sut.Update(&repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"})

        // 4. check that all expectations were met on the mock
        assert.Nil(t, err)
        assert.True(t, repoMock.AssertExpectations(t))
    })

    t.Run("BadUpdate", func(t *testing.T) {
        // 3. instantiate/setup mock
        repoMock := new(teamRepoMock)
        repoMock.On("GetByID", 1).Return(repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"}, nil).Times(1)
        repoMock.On("Update", repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"}).Return(errors.New("some error while updating")).Times(1)

        sut := NewTeamService(repoMock)
        err := sut.Update(&repo.Team{ID: 1, TeamOwnerID: 1, Name: "test"})

        // 4. check that all expectations were met on the mock
        assert.Equal(t, "some error while updating", err.Error())
        assert.True(t, repoMock.AssertExpectations(t))
    })
}
Copy after login

In the code you can find some comments to better detail what is happening. As you can guess, the problem is that this call is missing in the code:

repomock.on("getbyid", 1).return(repo.team{id: 1, teamownerid: 1, name: "test"}, nil).times(1)

If you run my solution it should work for you too.
If this solves your problem or you have any other questions, please let me know!

The above is the detailed content of Assertion: Mock: I don't know what to return because the method call was unexpected Error while writing unit test in Go. For more information, please follow other related articles on the PHP Chinese website!

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

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What libraries are used for floating point number operations in Go? What libraries are used for floating point number operations in Go? Apr 02, 2025 pm 02:06 PM

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

What is the problem with Queue thread in Go's crawler Colly? What is the problem with Queue thread in Go's crawler Colly? Apr 02, 2025 pm 02:09 PM

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

Which libraries in Go are developed by large companies or provided by well-known open source projects? Which libraries in Go are developed by large companies or provided by well-known open source projects? Apr 02, 2025 pm 04:12 PM

Which libraries in Go are developed by large companies or well-known open source projects? When programming in Go, developers often encounter some common needs, ...

What is the difference between `var` and `type` keyword definition structure in Go language? What is the difference between `var` and `type` keyword definition structure in Go language? Apr 02, 2025 pm 12:57 PM

Two ways to define structures in Go language: the difference between var and type keywords. When defining structures, Go language often sees two different ways of writing: First...

How to solve the user_id type conversion problem when using Redis Stream to implement message queues in Go language? How to solve the user_id type conversion problem when using Redis Stream to implement message queues in Go language? Apr 02, 2025 pm 04:54 PM

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...

In Go, why does printing strings with Println and string() functions have different effects? In Go, why does printing strings with Println and string() functions have different effects? Apr 02, 2025 pm 02:03 PM

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

What should I do if the custom structure labels in GoLand are not displayed? What should I do if the custom structure labels in GoLand are not displayed? Apr 02, 2025 pm 05:09 PM

What should I do if the custom structure labels in GoLand are not displayed? When using GoLand for Go language development, many developers will encounter custom structure tags...

Why is it necessary to pass pointers when using Go and viper libraries? Why is it necessary to pass pointers when using Go and viper libraries? Apr 02, 2025 pm 04:00 PM

Go pointer syntax and addressing problems in the use of viper library When programming in Go language, it is crucial to understand the syntax and usage of pointers, especially in...

See all articles