matryer / moq

Interface mocking tool for go generate
http://bit.ly/meetmoq
MIT License
1.96k stars 126 forks source link

Proposal: mocking function types #218

Open PeterEFinch opened 4 months ago

PeterEFinch commented 4 months ago

The idea: Adding the functionality to mock function types.

The motivation: Functions are first class objects that are passed into functions/methods and stored in structs. To test that we have the desired behaviour where they are being used it would be useful to be able to mock them in a similar fashion to interfaces.

What I am asking: Would you consider adding support for such functionality? See below for an example setup and expected result. N.B. I thought it useful to ask if you would consider it before I attempt to implement a solution.


The expectation would be that running go generate on

//go:generate moq -out mocks.go . Solver

// Solver represent a function that solves a problem that
// takes a long time.
type Solver func(ctx context.Context, in [][]int) ([]int, error)

yields something (along with suitable documentation) similar to

import (
    "context"
    "sync"
)

var _ Solver = (*SolverMock)(nil).Call

type SolverMock struct {
    Func func(ctx context.Context, in [][]int) ([]int, error)

    calls []struct {
        Ctx context.Context
        In  [][]int
    }

    mu sync.RWMutex
}

func (e *SolverMock) Call(ctx context.Context, in [][]int) ([]int, error) {
    if e.Func == nil {
        panic("SolverMock.Func: method is nil but Call was just called")
    }

    callInfo := struct {
        Ctx context.Context
        In  [][]int
    }{
        Ctx: ctx,
        In:  in,
    }

    e.mu.Lock()
    e.calls = append(e.calls, callInfo)
    e.mu.Unlock()

    return e.Func(ctx, in)
}

func (e *SolverMock) Calls() []struct {
    Ctx context.Context
    In  [][]int
} {
    var calls []struct {
        Ctx context.Context
        In  [][]int
    }
    e.mu.RLock()
    calls = e.calls
    e.mu.RUnlock()
    return calls
}