I'm attempting write a test for my package and failing at comparing funcs. Here's essentially what i'm doing.
package main
import (
"fmt"
"reflect"
)
type HandlerFunc func(cmd interface{})
type Bus struct {
handlers map[reflect.Type]HandlerFunc
}
func (bus *Bus) RegisterHandler(cmd interface{}, handler HandlerFunc) {
bus.handlers[reflect.TypeOf(cmd)] = handler
}
func (bus *Bus) GetHandler(cmd interface{}) HandlerFunc {
t := reflect.TypeOf(cmd)
for kind, handler := range bus.handlers {
if t == kind {
return handler
}
}
return nil
}
func New() *Bus {
return &Bus{
handlers: make(map[reflect.Type]HandlerFunc),
}
}
type RegisterUserCommand struct {}
func main() {
bus := New()
handler := func (cmd interface{}) {}
bus.RegisterHandler(&RegisterUserCommand{}, handler)
retrieved := bus.GetHandler(&RegisterUserCommand{})
if retrieved != handler {
fmt.Println("Not the same!")
return
}
fmt.Println("Same!")
}
Comparing retrieved with handler causes the following error
invalid operation: (func(interface {}))(retrieved) != handler (func can only be compared to nil)
How can i properly test the function i'm retrieving is the same one added previously?
Given that you can't compare functions, you can write your test in a different way. You can make handler set a boolean value in your test and check that you've got the right function by calling it and seeing if the boolean changes.
Here's an example:
func main() {
bus := New()
called := false
handler := func (cmd interface{}) { called = true }
bus.RegisterHandler(&RegisterUserCommand{}, handler)
bus.GetHandler(&RegisterUserCommand{})(nil)
if called {
fmt.Println("We got the right handler!")
return
}
fmt.Println("We didn't get the right handler")
}
Related
Last time I found out I didn't have to check if variable is nil to make singleton service but I can use sync.Once to achieve the same result, example below:
// instead of
var instance Instance
func NewInstance() {
if instance == nil {
instance = Instance{}
}
return instance
}
// can do this
var (
once sync.Once
instance Instance
)
func NewInstance() {
once.Do(func() {
instance = Instance{}
})
return instance
}
My question is:
Can I use sync package to break chaining rules and return error?
Desired result:
var (
breakChain sync.SomethingToBreakChain
err error
)
type s struct {}
func (s *s) F1() s {
err = service1.DoSomething()
// sync do something
return s
}
func (s *s) F2() s {
err = service2.DoSomething()
// sync do something
return s
}
func (s *s) F3() s {
err = service3.DoSomething()
// sync do something
return s
}
func (s *s) GetError() {
return err
}
func New() {
s := s{}
s.F1(). // if error save to `err` variable and break chain here prevent `F2` and `F3` to execute
F2(). // if error save to `err` variable and break chain here prevent `F3` to execute
F3() // if error save to `err` to return
err := s.GetError()
// do something with `err`
}
If you want to implement a chain like that, you might consider saving the error in the receiver itself and checking in every action:
type s struct {
e error
}
func (s *s) F1() *s {
if s.e!=nil {
return s
}
// Do things
if err:=doThings(); err!=nil {
s.e=err
}
return s
}
...
Otherwise, there are no mechanisms to prevent calling other methods in the chain.
I am using Echo framework and want to pass the Go's built-in context.Context underlying echo.Context after setting some custom values.
To achieve it, I think I could first apply Set(key string, val interface{}) method of echo.Context and then extract the underlying context.Context.
Question is is it possible to do it this way? In other words, does echo.Context.Set(...) sets the value directly on the context.Context just like WithValue does? Or should I take extra steps to copy my custom entries down.
P.S. I do not want to pass echo.Context to deeper layers of my app, that's why I do not want to directly use it but get the referring context.Context
Method 1: Reimplement the echo.Context.Get and echo.Context.Set methods to manipulate the ctx.Request().Context() object.
Disadvantages: http.Request.WithContext will be called once for each Set method, and *http.Request will be copied once. See the implementation of WithContext method for details.
Method 2: Reimplement the echo.Context.Get and echo.Context.Set methods to manipulate the contextValueData2 object, and set http.Request.WithContext to a custom context.Context contextValueData2.
Disadvantages: Before go1.13, context.Context requires Type assertions. Don't implement the context.Context method. Compared with method 1, the implementation only requires WithContext once.
It is recommended to use method 1, which is clear and simple, and method 2 is complicated and not fully tested.
The example import package uses gopath, and the implementation of this feature also reflects the advantage of echo.Context as an interface.
package main
import (
"context"
"fmt"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"net/http"
)
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(NewMiddlewareContextValue)
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.GET("/", hello)
e.GET("/val", getval)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
func getval(c echo.Context) error {
c.Set("111", "aa")
c.Set("222", "bb")
return c.String(http.StatusOK, fmt.Sprint(c.Request().Context()))
}
// ---------- method1 ----------
func NewMiddlewareContextValue(fn echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
return fn(contextValue{ctx})
}
}
type contextValue struct {
echo.Context
}
// Get retrieves data from the context.
func (ctx contextValue) Get(key string) interface{} {
// get old context value
val := ctx.Context.Get(key)
if val != nil {
return val
}
return ctx.Request().Context().Value(key)
}
// Set saves data in the context.
func (ctx contextValue) Set(key string, val interface{}) {
ctx.SetRequest(ctx.Request().WithContext(context.WithValue(ctx.Request().Context(), key, val)))
}
// ---------- method2 ----------
func NewMiddlewareContextValue2(fn echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctxdata := contextValueData2{
Context: ctx.Request().Context(),
}
ctx.SetRequest(ctx.Request().WithContext(ctxdata))
return fn(&contextValue2{Context: ctx, contextValueData2: ctxdata})
}
}
type contextValue2 struct {
echo.Context
contextValueData2
}
type contextValueData2 struct {
context.Context
Data map[string]interface{}
}
// Get retrieves data from the context.
func (ctx *contextValue2) Get(key string) interface{} {
// get old context value
val := ctx.Context.Get(key)
if val != nil {
return val
}
// get my data value
val, ok := ctx.contextValueData2.Data[key]
if ok {
return val
}
return ctx.contextValueData2.Context.Value(key)
}
// Set saves data in the context.
func (ctx *contextValue2) Set(key string, val interface{}) {
if ctx.Data == nil {
ctx.contextValueData2.Data = make(map[string]interface{})
}
ctx.contextValueData2.Data[key] = val
}
func (ctx contextValueData2) Value(key interface{}) interface{} {
str, ok := key.(string)
if ok {
val, ok := ctx.Data[str]
if ok {
return val
}
}
return ctx.Context.Value(key)
}
I have a set of functions, which uses the pool of objects. This pool has been mocked. It works fine in most of the cases. But in some functions i call the methods of objects from the pool. So i need to mock this objects too.
Lets say:
// ObjectGeter is a interface that is mocked
type ObjectGeter interface {
GetObject(id int) ObjectType, error
}
// this function is under test
func SomeFunc(og ObjectGeter,id int, otherArgument SomeType) error {
// some actions with otherArgument
// and may be return an error
obj, err := og.GetObject(id)
if err !=nil {
return errors.New("GetObject error")
}
rezult, err := obj.SomeMethod()
if err !=nil {
return errors.New("One of internal errors")
}
return rezult, nil
}
Is there a way to test whole this function? I can create interface SomeMethoder which wraps the SomeMethod(), but i can't find the way how to assign it to obj inside SomeFunc without changing the signature of GetObject to GetObject(id int) SomeMethoder,error.
Currently i see the one approach - testing by a parts.
The only solution i'v found without of changing of paradigm is a wrapper. It is pretty trivial but may be some one will need it once.
Originally i have some type:
type PoolType struct {...}
func (p *PoolType)GetObject(id int) (ObjectType, error) {...}
and interface, that wraps PoolType.GetObject and that i'v mocked.
Now i have the interface:
type SomeMethoder interface {
SomeMethod() (ResultType, error)
}
to wrap object returned by PoolType.GetObject().
To produce it i have interface:
type ObjectGeter interface {
GetObject(id int) (SomeMethoder, error)
}
and type
type MyObjectGeter struct {
pool *PoolType
}
func New(pool *PoolType) *MyObjectGeter {
return &MyObjectGeter{pool: pool}
}
func (p *MyObjectGeter)GetObject(id int) (SomeMethoder, error) {
return p.pool.GetObject(id)
}
that implements it.
So:
// this function is under test
func SomeFunc(og ObjectGeter,id int, otherArgument SomeType) error {
// some actions with otherArgument
// and may be return an error
iface, err := og.GetObject(id)
if err !=nil {
return errors.New("GetObject error")
}
rezult, err := iface.SomeMethod()
if err !=nil {
return errors.New("One of internal errors")
}
return rezult, nil
}
is called by
og := New(pool)
SomeFunc(og,id,otherArgument)
in real work.
After all to test whole SomeFunc i have to:
func TestSomeFuncSuccess (t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
objectGeter := mocks.NewMockObjectGeter(controller)
someMethoder := mocks.NewMockSomeMethoder(controller)
gomock.InOrder(
args.objectGeter.EXPECT().
GetObject(correctIdCOnst).
Return(someMethoder, nil),
args.someMethoder.EXPECT().
SomeMethod().
Return(NewResultType(...),nil).
Times(args.test.times[1]),
)
result, err := SomeFunc(objectGeter,correctIdCOnst,otherArgumentConst)
// some checks
}
So, the only untested part is MyObjectGeter.GetObject that is enough for me.
I'm trying to understand how to build a service container to go. Though it's not a recommended process still I want to learn something from it.
But after structuring code like this image below.
I'm getting an error message like this below.
Source code:
package unit
import (
"testing"
"github.com/stretchr/testify/assert"
framework "../../framework"
)
type ContainerFunc func(container Container) interface{}
type MyService struct {
Name string
}
type Container framework.Container
func TestContainerSingleton(t *testing.T) {
c := framework.New()
assert.False(t, c.Has("test.service.name"))
assert.Equal(t, []string{}, c.GetKeys())
c.Set("my.service", func(c Container) interface{} {
return &MyService{}
})
}
container.go
package framework
import (
"fmt"
"log"
"reflect"
"sync"
)
// Container is for containing any services
type Container interface {
Set(name string, f ContainerFunc)
Has(name string) bool
Get(name string) interface{}
GetKeys() []string
Fill(name string, ds interface{})
Extend(name string, f ExtenderFunc)
}
// ContainerFunc func will generate interfaces based on need
type ContainerFunc func(container Container) interface{}
// ExtenderFunc means interface
type ExtenderFunc interface{}
type container struct {
values map[string]ContainerFunc
extends map[string][]reflect.Value
services map[string]interface{}
mtx *sync.RWMutex
}
//New method initialize a new Container and returns it.
func New() Container {
return &container{
services: make(map[string]interface{}),
values: make(map[string]ContainerFunc),
extends: make(map[string][]reflect.Value),
mtx: &sync.RWMutex{},
}
}
/*
In Set method storing the container
*/
func (c *container) Set(name string, f ContainerFunc) {
c.mtx.Lock()
defer c.mtx.Unlock()
//Checking if the service is in the format, if service is there throw a panic
if _, ok := c.services[name]; ok {
log.Panic("Can not overwrite initialized service")
}
c.values[name] = f
fmt.Printf("%s service has been registered", name)
}
/*
Has Checks if the name exists in map and return boolean value
it first locks the c.values for reading then checks and at last using
defer it release the lock
*/
func (c *container) Has(name string) bool {
//applying read lock on value map
c.mtx.RLock()
//releasing lock after return call
defer c.mtx.RUnlock()
// Checking if the value exists or not, and put the boolean value into "ok" variable
if _, ok := c.values[name]; ok {
return true
}
return false
}
func (c *container) Get(name string) interface{} {
//locks reading from c.values
c.mtx.RLock()
_, ok := c.values[name]
//unlocking it after reading and put the boolean value into the ok variable
c.mtx.RUnlock()
//if its false panic a error
if !ok {
panic(fmt.Sprintf("The service does not exist: %s", name))
}
//if panic is not triggered
//read lock services from reading
c.mtx.RLock()
//check if the name is in the services
_, ok = c.services[name]
//read unlock the service map
c.mtx.RUnlock()
// the ok (boolean) is false type define container as c in "v" variable
if !ok {
v := c.values[name](c)
c.mtx.RLock()
c.services[name] = v
c.mtx.RUnlock()
// it itterates through the extends map and ....
if extends, ok := c.extends[name]; ok {
for _, extend := range extends {
//creating an slice of reflect value
result := extend.Call([]reflect.Value{reflect.ValueOf(v), reflect.ValueOf(c)})
c.mtx.Lock()
c.services[name] = result[0].Interface()
c.mtx.Unlock()
}
}
}
c.mtx.RLock()
defer c.mtx.RUnlock()
return c.services[name]
}
// Fill Returns error if anything happens
func (c *container) Fill(name string, dst interface{}) {
// getting the struct
obj := c.Get(name)
// added element the dst interface using fill funciton
if err := fill(obj, dst); err != nil {
log.Panic(err)
}
}
//Extend mainly have control over the c.extends , it is appending a callback function
func (c *container) Extend(name string, f ExtenderFunc) {
c.mtx.Lock()
defer c.mtx.Unlock()
if _, ok := c.services[name]; ok {
log.Panic("Cannnot extend initialized service")
}
if _, ok := c.values[name]; !ok {
log.Panicf("Cannot extend %s service", name)
}
c.extends[name] = append(c.extends[name], reflect.ValueOf(f))
}
// Get keys mainly creates a empty map , fill the map with all the value with string
//by appending and return the map
func (c *container) GetKeys() []string {
c.mtx.RLock()
defer c.mtx.RUnlock()
keys := make([]string, 0)
for k := range c.values {
keys = append(keys, k)
}
return keys
}
//fill method just add an element to the dest interface (which is being injected)
func fill(src, dest interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
d := reflect.TypeOf(dest)
s := reflect.TypeOf(src)
err = fmt.Errorf("The fill destination should be a pointer to a %s , but you used a %s", s, d)
}
}()
reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src))
return err
}
the error message I'm getting, Any idea how to solve this?:
Cannot use 'func(c Container) interface{} { return &MyService{} }'
(type func(c Container) interface{}) as type ContainerFunc
If I attempt to rebuild your situation (with Go 1.13) by constructing my own Framework from guesses—it would help if you showed us what is in Framework—the closest I can get is this:
./unit.go:25:22: cannot use func literal (type func(Container) interface {})
as type framework.ContainerFunc in argument to c.Set
which is due to this line:
type Container framework.Container
Changing it to:
type Container = framework.Container
so that this is an alias for the existing type makes the code build. (It would probably be better to just use framework.Container where appropriate, rather than defining your own unit.Container type.)
(If your IDE is dropping the framework. prefix from framework.Container, and otherwise shortening the Go compiler's error messages here, that would explain it.)
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
}