matryer / moq

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

Consider adding an optional "Hydrate" method for partial mocking #161

Closed kpurdon closed 1 year ago

kpurdon commented 2 years ago

Hi, love moq, so first of all thank you.

I wanted to propose an addition to the tool that I (and teams I've worked with) have added externally and find useful in certain cases. It's similar to the current stub option, but instead of zero values; it provides values from a real implementation of the interface. We often use this when we want to provide a partial mock for some side-effect during an otherwise complete integration test.

given:

package thinger

//go:generate moq -stub -fmt goimports -out thinger_mock.go . Thinger

type Thing struct {}

type Thinger interface {
    UpdateThing(t *Thing) error
    GetThing(id int) (*Thing, error)
}

add the following (optionally) to the generated mock:

func (mock *ThingerMock) Hydrate(t Thinger) {
    if mock.GetThingFunc == nil {
        mock.GetThingFunc = t.GetThing
    }
    if mock.UpdateThingFunc == nil {
        mock.UpdateThingFunc = t.UpdateThing
    }
}

This would be optional via -hyrdate (or another name). I'm also more than happy to implement this. Thoughts?

breml commented 2 years ago

@kpurdon Thanks for the proposal and the PR.

I use moq since many years and I never had this requirement myself. But I understand the reasoning behind it and I can envision situations in the future, where this feature would become handy. To me, this addition sounds like an addition, that is worth the cost, given the simplicity of the implementation.

matryer commented 2 years ago

@kpurdon is it possible to do the same thing directly?

realThing := NewRealThing()
mockedThing := &ThingerMock{
  GetThing: realThing.GetThing,
}
// or 
mockedThing.UpdateThingFunc = realThing.UpdateThingFunc

I wonder if adding docs to explain this technique (which is pretty cool btw, and not something I've seen before) would be an acceptable alternative to adding a method?

kpurdon commented 2 years ago

@matryer yes; it definitely possible to do this manually/directly. However, the most often use case that has led us to this is providing a complete real implementation and only mocking a couple of functions. While this probably does boil down to just adding a few manual things it's much cleaner/simpler to just call mockThing.Hydrate(realThing) and given the simplicity of adding it as an optional add-on to moq feels worthy.

kpurdon commented 2 years ago

@matryer, stalled again here -- anything I can do to get this added? Thanks.

breml commented 2 years ago

As mentioned earlier, I am for the inclusion of this feature, because it is limited to a simple helper and does not really extend the API surface at the core of moq. As the main advantage I see the automated updating of the hydrated methods whenever the underlying interfaces changes (in this case, moq or go generate have to be executed anyway). To make this possibility (combine mock and real implementation) more obvious, the PR #162 should also update the README.md to mention this flag and maybe highlight the use of it in the Tips section.

kpurdon commented 2 years ago

Thanks @breml -- I'm happy to add anything (README, docs, ...) if this will be accepted/reviewed by @matryer.