Here is the sample code for the struct and its method
type A struct {}
func (a *A) perfom(string){
...
...
..
}
Then i want to call the method from the function invoke() present outside the package, sample code
var s := A{}
func invoke(url string){
out := s.perfom(url)
...
...
}
Now, i want to write the test case for invoke function by mocking the perfom method of A.
In jave, we had mockito,jmock framework to stud method calls.
Is there any way in go, we can mock the method call of the struct with out introducing Interfaces in source code? or any good mocking framework in go is there ?
In your test, write a mock function func mockPerform(s string) and pass it into invoke:
invoke(url, mockPerform)
EDIT: The second option is plain wrong. See comment #6.
Get rid of the global variable s. (This is a general advice - avoid global variables.) Change invoke to include the struct as a parameter:
func invoke(url string, s A) {
...
}
...
s := A{}
invoke(url, s)
and then write a mock struct with mock functions and pass it to invoke:
type mockA struct{}
func (m *mockA) perform(s string) {
...
}
// in your test function:
m := mockA{}
invoke(url, m)
Both approaches need no interface and no mocking framework. The “secret” is to avoid hardcoded dependencies on entities outside the function you want to test. Pass them as parameters instead.
@christophberger I tried 2 solution, calling invoke from test method by passing mockA{} in my test function, It gave me compilation error cannot use m (type mockA) as type A in argument to invoke
You’re right, my bad. I wrote this code too quickly and did not test it. For the second option, you need an interface. Let me start from the beginning.
Your library package needs no change. Well, one change: Use a capital P for method Perform to make it visible outside the package.
For testing purposes, I also added a return parameter.
perf/perf.go:
package perf
type A struct{}
func (a *A) Perform(s string) int {
return len(s)
}
In main, you define an interface:
main.go:
package main
import (
"fmt"
"perf" // adjust this path depending on where you put perf
)
type Performer interface {
Perform(string) int
}
func invoke(url string, p Performer) int {
return p.Perform(url)
}
func main() {
a := perf.A{}
url := "https://appliedgo.net" // shameless plug :-)
fmt.Println(invoke(url, &a)) // We need to pass a pointer here because Perform() has a pointer receiver
}
And in your test file, create and use mockA. Invoke() will accept it as it implements the Performer interface:
invoke_test.go:
package main
import "testing"
type mockA struct{}
func (m *mockA) Perform(s string) int {
return len(s)
}
func Test_invoke(t *testing.T) {
m := mockA{}
url := "https://appliedgo.net"
want := 21
if got := invoke(url, &m); got != want {
t.Errorf("invoke() = %v, want %v", got, want)
}
}