Suppose I have a dependency that looks like this:
type Dependency interface {
Retrieve(transform func(row *Row) string) []string
}
And I'm using it in code that I'd like to unit test
// ...
result := dep.Retrieve(func(row *Row) string {
// ... do stuff
})
// ...
This is a contrived example, but consider it for something like gcloud pubsub, which has a Receive method that calls a user-defined function for each message it pulls.
If I use mockgen to get a mock of Dependency, how do I tell the mock how to behave? I'd want it to call its input function some number of times with some sets of input.
Here is some code while trying to understand what you wanted to achieve.
I don't use mockgen, but manually, you can do what you want. I totally changed the behavior between the original and the mocked call. Does it answer your questions?
package main
import (
"fmt"
)
var str = [...]string{
"world",
"night",
}
type Dependency interface {
Get(val string) string
}
type dependency struct {
i int
}
func (d *dependency) Get(fn func(int) string) string {
d.i++
d.i = d.i % len(str)
return "hello " + fn(d.i)
}
func main() {
d := dependency{}
myfn := func(idx int) string { return str[idx] }
fmt.Println(d.Get(myfn))
fmt.Println(d.Get(myfn))
fmt.Println(d.Get(myfn))
m := mock{}
fmt.Println(m.Get(myfn))
}
type mock struct {
}
func (m *mock) Get(fn func(int) string) string {
i := 0
j := (i + 1) % len(str)
k := (j + 1) % len(str)
return "mocked " + fn(i) + fn(j) + fn(k)
}
The play link:
https://play.golang.org/p/bb7WrmlIEN
Related
Let's say we have a library provide a function Double to double the integer, we use pointer i to get the result value not by return:
package api
type Action interface {
Double(i *int) error
}
type NUM struct{}
func (n NUM) Double(i *int) error {
*i *= 2
return nil
}
in our main function we use this library to do our task. like this:
package app
import (
"fmt"
"github.com/hotsnow/api"
)
func main() {
j := job{a: &api.NUM{}}
d := j.task(3)
fmt.Println(3, d)
}
type job struct {
a api.Action
}
// double me
func (j job) task(i int) int {
j.a.Double(&i)
return i
}
Now we need to test the task() function, how can we get the pointer return bye mock the Double function?
Here is the test:
package app
import (
"github.com/golang/mock/gomock"
"github.com/hotsnow/mocks"
"testing"
)
func TestReq(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := mocks.NewMockAction(ctrl)
m.EXPECT().Double(gomock.Any()).Return(nil)
j := job{a: m}
got := j.task(3)
if got != 6 {
t.Errorf("got = %#v; want 6", got)
}
}
The code here: https://github.com/hotsnow/mock.git (stackoverflow branch)
you can use gomock setarg function for this
yourPackage.EXPECT().insert(&pointer).SetArg(0, newPointer)
You can achieve this with the provided Eq() matcher, which internally calls reflect.DeepEqual() on the expected and actual values; as per the documentation for this method:
Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.
Say we have a function that depends upon an interface method that takes a pointer parameter:
package resource
type ServiceRequest struct {
Name string
Owner *string // this is a pointer so it can be omitted with `nil`
}
type Model struct {
// resource model...
}
type ResourceService interface {
Fetch(req *ServiceRequest) (Model, error)
}
type getResourceHandler struct {
resourceService ResourceService
}
type GetResourceEvent struct {
Resource string
Owner *string
}
func NewResourceHandler(resourceService ResourceService) *getResourceHandler {
return &getResourceHandler{resourceService}
}
func (h *getResourceHandler) Handle(event GetResourceEvent) (Model, error) {
return h.resourceService.Fetch(&ServiceRequest{event.Resource, event.Owner})
}
We can use the Eq() matcher when setting up the expectation against our generated mock of the ResourceService interface:
package test
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/org/repo/internal/mock"
"github.com/org/repo/internal/resource"
)
func optionalString(str string) *string {
return &str
}
func Test_GetResourceHandler_ReturnsResultFromService(t *testing.T) {
resourceName := "my-resource"
owner := optionalString("Joe Bloggs")
resourceReq := &resource.ServiceRequest{resourceName, owner}
event := resource.GetResourceEvent{resourceName, owner}
model := resource.Model{ /* fields here... */ }
ctrl := gomock.NewController(t)
mockResourceService := mock.NewMockResourceService(ctrl)
handler := resource.NewResourceHandler(mockResourceService)
mockResourceService.EXPECT().Fetch(gomock.Eq(resourceReq)).Return(model, nil)
res, err := handler.Handle(event)
assert.Nil(t, err)
assert.Equal(t, model, res)
}
If you change the contents of the service request in either the test or the unit under test, you'll see that the test no longer passes. Otherwise, it will pass in spite of the test and the unit under test having their own respective pointers to separate ServiceRequest{} values.
It seems you don't have to use gomock to test the task method.
Since you have an interface, why not just create a mock implementation of the interface, for example:
type dummy struct{
callCount int
}
func (d *dummy) Double(i *int) error {
d.callCount++
return nil
}
d := dummy{}
j := job{a: &d}
got := j.task(3)
if d.callCount != 1 {
// XXX
}
I have a package named "seeder":
package seeder
import "fmt"
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
Now I want to call all functions with MyFunc prefix
package main
import "./seeder"
func main() {
for k := 1; k <= 3; k++ {
seeder.MyFunc1() // This calls MyFunc1 three times
}
}
I want something like this:
for k := 1; k <= 3; k++ {
seeder.MyFunc + k ()
}
and this output:
I am Masood
I am a programmer
I want to buy a car
EDIT1:
In this example, parentKey is a string variable which changed in a loop
for parentKey, _ := range uRLSjson{
pppp := seeder + "." + strings.ToUpper(parentKey)
gorilla.HandleFunc("/", pppp).Name(parentKey)
}
But GC said:
use of package seeder without selector
You can't get a function by its name, and that is what you're trying to do. The reason is that if the Go tool can detect that a function is not referred to explicitly (and thus unreachable), it may not even get compiled into the executable binary. For details see Splitting client/server code.
With a function registry
One way to do what you want is to build a "function registry" prior to calling them:
registry := map[string]func(){
"MyFunc1": MyFunc1,
"MyFunc2": MyFunc2,
"MyFunc3": MyFunc3,
}
for k := 1; k <= 3; k++ {
registry[fmt.Sprintf("MyFunc%d", k)]()
}
Output (try it on the Go Playground):
Hello MyFunc1
Hello MyFunc2
Hello MyFunc3
Manual "routing"
Similar to the registry is inspecting the name and manually routing to the function, for example:
func callByName(name string) {
switch name {
case "MyFunc1":
MyFunc1()
case "MyFunc2":
MyFunc2()
case "MyFunc3":
MyFunc3()
default:
panic("Unknown function name")
}
}
Using it:
for k := 1; k <= 3; k++ {
callByName(fmt.Sprintf("MyFunc%d", k))
}
Try this on the Go Playground.
Note: It's up to you if you want to call the function identified by its name in the callByName() helper function, or you may choose to return a function value (of type func()) and have it called in the caller's place.
Transforming functions to methods
Also note that if your functions would actually be methods of some type, you could do it without a registry. Using reflection, you can get a method by name: Value.MethodByName(). You can also get / enumerate all methods without knowing their names using Value.NumMethod() and Value.Method() (also see Type.NumMethod() and Type.Method() if you need the name of the method or its parameter types).
This is how it could be done:
type MyType int
func (m MyType) MyFunc1() {
fmt.Println("Hello MyFunc1")
}
func (m MyType) MyFunc2() {
fmt.Println("Hello MyFunc2")
}
func (m MyType) MyFunc3() {
fmt.Println("Hello MyFunc3")
}
func main() {
v := reflect.ValueOf(MyType(0))
for k := 1; k <= 3; k++ {
v.MethodByName(fmt.Sprintf("MyFunc%d", k)).Call(nil)
}
}
Output is the same. Try it on the Go Playground.
Another alternative would be to range over an array of your functions
package main
import (
"fmt"
)
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
func main() {
for _, fn := range []func(){MyFunc1, MyFunc2, MyFunc3} {
fn()
}
}
I have a package named "seeder":
package seeder
import "fmt"
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
Now I want to call all functions with MyFunc prefix
package main
import "./seeder"
func main() {
for k := 1; k <= 3; k++ {
seeder.MyFunc1() // This calls MyFunc1 three times
}
}
I want something like this:
for k := 1; k <= 3; k++ {
seeder.MyFunc + k ()
}
and this output:
I am Masood
I am a programmer
I want to buy a car
EDIT1:
In this example, parentKey is a string variable which changed in a loop
for parentKey, _ := range uRLSjson{
pppp := seeder + "." + strings.ToUpper(parentKey)
gorilla.HandleFunc("/", pppp).Name(parentKey)
}
But GC said:
use of package seeder without selector
You can't get a function by its name, and that is what you're trying to do. The reason is that if the Go tool can detect that a function is not referred to explicitly (and thus unreachable), it may not even get compiled into the executable binary. For details see Splitting client/server code.
With a function registry
One way to do what you want is to build a "function registry" prior to calling them:
registry := map[string]func(){
"MyFunc1": MyFunc1,
"MyFunc2": MyFunc2,
"MyFunc3": MyFunc3,
}
for k := 1; k <= 3; k++ {
registry[fmt.Sprintf("MyFunc%d", k)]()
}
Output (try it on the Go Playground):
Hello MyFunc1
Hello MyFunc2
Hello MyFunc3
Manual "routing"
Similar to the registry is inspecting the name and manually routing to the function, for example:
func callByName(name string) {
switch name {
case "MyFunc1":
MyFunc1()
case "MyFunc2":
MyFunc2()
case "MyFunc3":
MyFunc3()
default:
panic("Unknown function name")
}
}
Using it:
for k := 1; k <= 3; k++ {
callByName(fmt.Sprintf("MyFunc%d", k))
}
Try this on the Go Playground.
Note: It's up to you if you want to call the function identified by its name in the callByName() helper function, or you may choose to return a function value (of type func()) and have it called in the caller's place.
Transforming functions to methods
Also note that if your functions would actually be methods of some type, you could do it without a registry. Using reflection, you can get a method by name: Value.MethodByName(). You can also get / enumerate all methods without knowing their names using Value.NumMethod() and Value.Method() (also see Type.NumMethod() and Type.Method() if you need the name of the method or its parameter types).
This is how it could be done:
type MyType int
func (m MyType) MyFunc1() {
fmt.Println("Hello MyFunc1")
}
func (m MyType) MyFunc2() {
fmt.Println("Hello MyFunc2")
}
func (m MyType) MyFunc3() {
fmt.Println("Hello MyFunc3")
}
func main() {
v := reflect.ValueOf(MyType(0))
for k := 1; k <= 3; k++ {
v.MethodByName(fmt.Sprintf("MyFunc%d", k)).Call(nil)
}
}
Output is the same. Try it on the Go Playground.
Another alternative would be to range over an array of your functions
package main
import (
"fmt"
)
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
func main() {
for _, fn := range []func(){MyFunc1, MyFunc2, MyFunc3} {
fn()
}
}
Is there anyway to make a map of function pointers, but functions that take recievers? I know how to do it with regular functions:
package main
func someFunc(x int) int {
return x
}
func main() {
m := make(map[string]func(int)int, 0)
m["1"] = someFunc
print(m["1"](56))
}
But can you do that with functions that take recievers? Something like this (though I've tried this and it doesn't work):
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string](someStruct)func()int, 0)
s := someStruct{56}
m["1"] = someFunc
print(s.m["1"]())
}
An obvious work around is to just pass the struct as a parameter, but that's a little dirtier than I would have liked
You can do that using Method Expressions:
https://golang.org/ref/spec#Method_expressions
The call is a bit different, since the method expression takes the receiver as the first argument.
Here's your example modified:
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string]func(someStruct)int, 0)
s := someStruct{56}
m["1"] = (someStruct).someFunc
print(m["1"](s))
}
And here's a Go playground for you to test it:
https://play.golang.org/p/PLi5A9of-U
Is it possible to work similar way like the function overloading or optional parameter in C# using Golang? Or maybe an alternative way?
The idiomatic answer to optional parameters in Go is wrapper functions:
func do(a, b, c int) {
// ...
}
func doSimply(a, b) {
do(a, b, 42)
}
Function overloading was intentionally left out, because it makes code hard(er) to read.
Neither function overloading nor optional arguments are directly supported. You could work around them building your own arguments struct. I mean like this (untested, may not work...) EDIT: now tested...
package main
import "fmt"
func main() {
args:=NewMyArgs("a","b") // filename is by default "c"
args.SetFileName("k")
ret := Compresser(args)
fmt.Println(ret)
}
func Compresser(args *MyArgs) string {
return args.dstFilePath + args.srcFilePath + args.fileName
}
// a struct with your arguments
type MyArgs struct
{
dstFilePath, srcFilePath, fileName string
}
// a "constructor" func that gives default values to args
func NewMyArgs(dstFilePath string, srcFilePath string) *MyArgs {
return &MyArgs{
dstFilePath: dstFilePath,
srcFilePath:srcFilePath,
fileName :"c"}
}
func (a *MyArgs) SetFileName(value string){
a.fileName=value;
}
There are some hints here using variadic arguments, for example:
sm1 := Sum(1, 2, 3, 4) // = 1 + 2 + 3 + 4 = 10
sm2 := Sum(1, 2) // = 1 + 2 = 3
sm3 := Sum(7, 1, -2, 0, 18) // = 7 + 1 + -2 + 0 + 18 = 24
sm4 := Sum() // = 0
func Sum(numbers ...int) int {
n := 0
for _,number := range numbers {
n += number
}
return n
}
Or ...interface{} for any types:
Ul("apple", 7.2, "BANANA", 5, "cHeRy")
func Ul(things ...interface{}) {
fmt.Println("<ul>")
for _,it := range things {
fmt.Printf(" <li>%v</li>\n", it)
}
fmt.Println("</ul>")
}
An approach I use sometime for constructing an object using New methods having different arguments is to have a "flavor" pseudo type. You can try it on the Go Playground https://play.golang.org/p/5To5AcY-MRe
package main
import "fmt"
type flavorA struct{}
type flavorB struct{}
var FlavorA = flavorA{}
var FlavorB = flavorB{}
type Something struct {
i int
f float64
}
func (flavor flavorA) NewSomething(i int) *Something {
return &Something{i:i, f:0.0}
}
func (flavor flavorB) NewSomething(f float64) *Something {
return &Something{i:0, f:f}
}
func main() {
fmt.Println(FlavorA.NewSomething(1), FlavorB.NewSomething(2))
}
When you have many arguments it may make sense to use a new struct for them or to define a new MyOptionBuilder type to build and store all the arguments and to construct nice defaults.
Here's a simple example where the go defaults for types are okay.
package main
import "fmt"
type FancyFuncOptions struct {
I int64
S string
F float64
//...many more...
}
func FancyFunc(opts *FancyFuncOptions) {
fmt.Println("%v", opts)
}
func main() {
// simple way
options := &FancyFuncOptions{S: "happy"}
FancyFunc(options)
In golang you'll see people using method-chaining for this, if the options have complex logic.
package main
import "fmt"
type FancyFuncOptions struct {
I int64
S string
F float64
//...many more...
}
// chaining style
func NewFancyFuncOptions() *FancyFuncOptions {
return &FancyFuncOptions{I: 100, S: "empty", F: 0.1}
}
func (o *FancyFuncOptions) SetI(i int64) *FancyFuncOptions {
o.I = i
return o
}
func (o *FancyFuncOptions) SetS(s string) *FancyFuncOptions {
o.S = s
return o
}
func FancyFunc(opts *FancyFuncOptions) {
fmt.Println("%v", opts)
}
func main() {
// fancier
options = NewFancyFuncOptions().SetI(234).SetS("happy")
FancyFunc(options)
(https://go.dev/play/p/Ae_6Y6kZa97)
Make sense?