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.
Related
I'm doing some experimentation with type parameters to come up with a generic way of wiring up structs that generate a response to JSON HTTP requests.
The Method interface which the structs must implement has a SetParams method. This will work as expected as long as the implementation uses a pointer receiver.
My question: Is there any way of making this a compile time error if SetParams has a value receiver?
Here is an example demonstrating the problem with a SetParams that has a value receiver:
package main
import (
"encoding/json"
"fmt"
"log"
)
type PingParams struct {
Name string
}
type PingResponse struct {
Message string
}
func (p PingParams) Greeting() string {
if p.Name != "" {
return fmt.Sprintf("Hello, %s", p.Name)
}
return fmt.Sprintf("Hello, nobody!")
}
type GoodPing struct {
Params PingParams
}
// SetParams has a pointer receiver.
func (m *GoodPing) SetParams(p PingParams) {
fmt.Printf("assign %v with pointer receiver, Good!\n", p)
m.Params = p
}
func (m GoodPing) Run() (*PingResponse, error) {
return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}
type BadPing struct {
Params PingParams
}
// SetParams has a value receiver.
func (m BadPing) SetParams(p PingParams) {
fmt.Printf("assign %v with value receiver, Bad!\n", p)
m.Params = p
}
func (m BadPing) Run() (*PingResponse, error) {
return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}
type Method[M, RQ, RS any] interface {
// Run builds the RPC result.
Run() (*RS, error)
// SetParams is intended to set the request parameters in the struct implementing the RPC method.
// This then allows the request parameters to be easily available to all methods of the Method struct.
// The method MUST have a pointer receiver. This is NOT enforced at compile time.
SetParams(p RQ)
// The following line requires the implementing type is a pointer to M.
*M
// https://stackoverflow.com/a/72090807
}
func HandlerMethod[M, RQ, RS any, T Method[M, RQ, RS]](in json.RawMessage) (*RS, error) {
// A real implementation of this would return a func for wiring into a request router
var req RQ
err := json.Unmarshal(in, &req)
if err != nil {
return nil, err
}
var m T = new(M)
m.SetParams(req)
return m.Run()
}
func main() {
payload := []byte(`{"Name": "Mark"}`)
bad, err := HandlerMethod[BadPing, PingParams, PingResponse](payload)
if err != nil {
log.Fatal(err)
}
fmt.Println(bad.Message)
good, err := HandlerMethod[GoodPing, PingParams, PingResponse](payload)
if err != nil {
log.Fatal(err)
}
fmt.Println(good.Message)
}
https://go.dev/play/p/Eii8ADkmDxE
You can't do that.
When in your code you do this:
var m T = new(M)
even if T's type set includes only *M as a type term, *M's method set includes methods declared on M. The compiler can't check for you how the method ends up in *M's method set.
It is your responsibility when declaring the method SetParam on BadPing to make sure that the method doesn't attempt to unfruitfully modify the receiver.
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.
In Go, how would I test that a mock dependency has been called in the correct way.
If I have a struct that takes a interface for a dependency, after injection I want to be able to test the original mock object has been called.
My current code in this example I can not see that the struct value has changed. If I change my code to pass by reference it triggers the error:
s.simpleInterface.Call undefined (type *SimpleInterface is pointer to interface, not interface)
type SimpleInterface interface {
Call()
}
type Simple struct {
simpleInterface SimpleInterface
}
func (s Simple) CallInterface() {
s.simpleInterface.Call()
}
type MockSimple struct {
hasBeenCalled bool
}
func (ms MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
I see three easy ways to fix this:
1- Change the signature of the Call method to receive a pointer to MockSimple, and when instantiating the Simple struct, give it the address of your mock:
func (ms *MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: &ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
2- Not the cleanest solution, but still works. Use it if you really cant use #1. Declare "hasBeenCalled" somewhere else and change your MockSimple to hold a pointer to it:
type MockSimple struct {
hasBeenCalled *bool
}
func (ms MockSimple) Call() {
*ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
hasBeenCalled := false
ms := MockSimple{&hasBeenCalled}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
3- Probably a really bad solution: using globals, so I would only use it as a last resort (always avoid global state). Make "hasBeenCalled" a global and modify it from the method.
var hasBeenCalled bool
type MockSimple struct{}
func (ms MockSimple) Call() {
hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
Cheers!
Suppose I have two package like
-a
-b
a have some methods like this
func TestOne() { //something }
func TestTwo() { //something }
I need to call package a's methods from package b but by only string method name. Like i get the string "TestOne" and calls for the method TestOne(). How can i get that done.
Edit :
I have Read about reflect. but reflect needs an struct and functions be a member of that struct. What if My functions are not member of a struct? just plain methods in a package. and the calling methods and called methods are in different package. Then?
NB. There could be some methods that have parameters as well.
Like LightWeight said in his answer, you can use reflection.
You use the reflect.ValueOf method to get the value of the type. Then you can use the MethodByName method to get the function value. Once you have the function value you can call the Call method to execute it.
Code Sample
package main
import (
"fmt"
"reflect"
)
type TypeOne struct {
}
func (t *TypeOne) FuncOne() {
fmt.Println("FuncOne")
}
func (t *TypeOne) FuncTwo(name string) {
fmt.Println("Hello", name)
}
func CallFuncByName(myClass interface{}, funcName string, params ...interface{}) (out []reflect.Value, err error) {
myClassValue := reflect.ValueOf(myClass)
m := myClassValue.MethodByName(funcName)
if !m.IsValid() {
return make([]reflect.Value, 0), fmt.Errorf("Method not found \"%s\"", funcName)
}
in := make([]reflect.Value, len(params))
for i, param := range params {
in[i] = reflect.ValueOf(param)
}
out = m.Call(in)
return
}
func main() {
t1 := &TypeOne{}
out, err := CallFuncByName(t1, "FuncOne")
if err != nil {
panic(err)
}
//Return value
_ = out
out, err = CallFuncByName(t1, "FuncTwo", "monkey")
if err != nil {
panic(err)
}
//Return value
_ = out
}
You can try to use reflect in go. This link may be help you
https://golang.org/pkg/reflect/
and http://mikespook.com/2012/07/function-call-by-name-in-golang/
func foo() {
// bla...bla...bla...
}
func bar(a, b, c int) {
// bla...bla...bla...
}
funcs := map[string]interface{}{"foo":foo, "bar":bar}
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")
}