I am having trouble writing unit tests in Go for a rather common use-case/pattern.
Imagine, if you will, something like this:
package main
type Resource struct {
name string
}
type ResourceManager interface {
GetResource(id string) (*Resource, error)
GetAllResources() ([]*Resource, error)
}
type ResourceManagerImpl struct {
}
func (r *ResourceManagerImpl) GetResource(id string) (*Resource, error) {
resource := &Resource{}
var err error
// fetch resource.
// ...
return resource, err
}
func (r *ResourceManagerImpl) GetAllResources() ([]*Resource, error) {
var resources []*Resource
var err error
// for _, id := range ids {
// resource = r.GetResource(id)
// resources = append(resources, resource)
// }
return resources, err
}
It's a common pattern to have the GetAllResources
invoke GetResource
repeatedly as-needed.
I can use gomock
or testify
to test all permutations of GetResource
. But, when testing GetAllResource
, I'd like to mock GetResource
. Otherwise, testing would become sort-of-a nightmare. This is how one would do it in easymock
or mockito
in case of Java using partial mocks. But, it's not clear how the same could be achieved in Golang.
Specifically, I couldn't find how to partially mock the struct
. Most suggestions revolve around breaking such struct
s but in this case, the struct
is already at its bare minimum. It seems like a fair ask to not break the ResourceManager
interface (into single and multi) for the sake of testing as that would not make much sense and would be kludgy at best and wouldn't scale well as more such methods make into the interface.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/3c22e3fc-b3ad-47e7-9e41-400856423e58%40googlegroups.com.
Specifically, I couldn't find how to partially mock the
struct
. Most suggestions revolve around breaking suchstruct
s but in this case, thestruct
is already at its bare minimum. It seems like a fair ask to not break theResourceManager
interface (into single and multi) for the sake of testing as that would not make much sense and would be kludgy at best and wouldn't scale well as more such methods make into the interface.
On Thu, 12 Dec 2019, at 10:27 PM, karth...@gmail.com wrote:Specifically, I couldn't find how to partially mock the
struct
. Most suggestions revolve around breaking suchstruct
s but in this case, thestruct
is already at its bare minimum. It seems like a fair ask to not break theResourceManager
interface (into single and multi) for the sake of testing as that would not make much sense and would be kludgy at best and wouldn't scale well as more such methods make into the interface.I think your problems likely stem from having interfaces that are too large. Interfaces in Go are more flexible than in many other languages since there is no "implements" keyword that binds a struct to a particular interface. This means that you can have many more specialised interfaces that your struct may automatically satisfy.One consequence of this is that In Go it is usually preferable to define the interface where it is consumed instead of where the implementations are. This tends to make interfaces smaller, having just the methods needed for the consumer. It also implies that testing via the interface is the wrong approach.
First write your tests against the struct to verify that getting one or all resources work.
Break the interface into smaller specialised ones and move them next to the consuming code. In your case you may have an endpoint that uses a GetResource method, so you define that interface. Another endpoint may need just the GetAllResources method: another interface. You can then test your endpoints by supplying a test struct that implements the smaller interface needed.
-- Ian