I'm pretty new to go. I'm trying to mock a single method of a struct using testify, but I don't know how to do it.
Here's the code:
type HelloWorlder interface {
SayHello() string
GetName() string
}
type HelloWorld struct{}
func (hw *HelloWorld) SayHello() string {
return fmt.Sprintf("Hello World from %s!", hw.GetName())
}
func (hw *HelloWorld) GetName() string {
return "se7entyse7en"
}
and here's the test:
type MockHelloWorld struct {
mock.Mock
HelloWorld
}
func (m *MockHelloWorld) GetName() string {
args := m.Called()
return args.String(0)
}
type SomeTestSuite struct {
suite.Suite
}
func (s *SomeTestSuite) TestMocking() {
mhw := new(MockHelloWorld)
mhw.On("GetName").Return("foo bar")
fmt.Println(mhw.SayHello())
}
The idea is to mock only the GetName method so that it prints Hello World from foo bar!. Is that possible?
For those familiar with Python, what I'm trying to achieve is similar to what the unittest.Mock class permits through the wraps argument.
UPDATE
The imported packages from testify are these:
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
Maybe this will help you.
package main
import (
"fmt"
"github.com/stretchr/testify/mock"
)
type userReader interface {
ReadUserInfo(int) int
}
type userWriter interface {
WriteUserInfo(int)
}
type UserRepository struct {
userReader
userWriter
}
type realRW struct{}
func (db *realRW) ReadUserInfo(i int) int {
return i
}
func (db *realRW) WriteUserInfo(i int) {
fmt.Printf("put %d to db.\n", i)
}
// this is mocked struct for test writer.
type MyMockedWriter struct {
mock.Mock
}
func (m *MyMockedWriter) ReadUserInfo(i int) int {
args := m.Called(i)
return args.Int(0)
}
func main() {
rw := &realRW{}
repo := UserRepository{
userReader: rw,
userWriter: rw,
}
fmt.Println("Userinfo is:", repo.ReadUserInfo(100))
repo.WriteUserInfo(100)
// when you want to write test.
fmt.Println("Begin test....................")
testObj := new(MyMockedWriter)
testObj.On("ReadUserInfo", 123).Return(250)
testRepo := UserRepository{
userReader: testObj,
userWriter: rw,
}
fmt.Println("Userinfo is:", testRepo.ReadUserInfo(123))
testRepo.WriteUserInfo(100)
}
// Output:
// Userinfo is: 100
// put 100 to db.
// Begin test....................
// Userinfo is: 250
// put 100 to db.
Good luck.
Related
I want to build a testing part for my http handlers, and I want to use the http handler functions how they are, but I want to have separate functions that mock the db part of the handling. What I have in mind is something like:
package main
import (
"log"
"testing"
)
// DB functions
type UserDBFunctions interface {
InsertUser() string
}
type UserDB struct {
}
func (u UserDB) InsertUser() string {
return "hello"
}
// http handler functions
type UserHandlerFunctions interface {
Register() string
}
type UserHandler struct {
userDb *UserDB
}
func newUserHandler() UserHandler {
return UserHandler{userDb: new(UserDB)}
}
func (u UserHandler) Register() string {
str := u.userDb.InsertUser()
return str + " world"
}
func main() {
var i UserHandlerFunctions = newUserHandler()
str := i.Register()
log.Println(str)
}
// test functions
type FakeUserDBFunctions interface {
InsertUser() string
}
type FakeUserDB struct {
}
func (u FakeUserDB) InsertUser() string {
return "bye"
}
func newFakeUserHandler() UserHandler {
return UserHandler{userDb: *UserDB(&FakeUserDB{})}
}
func TestRegisterUser(t *testing.T) {
t.Run("register user", func(t *testing.T) {
var i UserHandlerFunctions = newFakeUserHandler()
str := i.Register()
log.Println(str)
})
}
So the first interface is for the real db functions, then there is the http handler which calls the db function and below the main() function there should be the tests with a mockup of the db function. But this part doesn't work. How do I replace the real interface in the newUserHandler by a mockup.
I would really appreciate help. 😊
The UseHandler shall use UserDBFunctions instead of UserDB.
type UserHandler struct {
userDb UserDBFunctions
}
Here is the modified one https://play.golang.org/p/nLiaomKA2NH
I am trying to imitate what is happening in error in a similar piece of code, first piece of code prints --- log second does not why? or in other words I am trying to understand how Error() method got called without explicitly calling.
package main
import (
"fmt"
)
type argError struct {
arg int
prob string
}
func (e *argError) Error() string {
return fmt.Sprintf("%d ---- %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
return -1, &argError{arg, "can't work with it"}
}
func main() {
a,b := f2(42)
fmt.Println(a)
fmt.Println(b)
}
package main
import (
"fmt"
)
type myerr interface {
Apple() string
}
type dummy struct {
age int
name string
}
func (d *dummy) Apple() string {
return fmt.Sprintf("%d --- %s", d.age, d.name)
}
func f1(arg int) (string, myerr) {
return "f1", &dummy{arg, "ret"}
}
func main() {
i, j := f1(42)
fmt.Println(i)
fmt.Println(j)
}
To make it work, your type has to implement the error interface by having a Error method. I recommend adjusting your myerr interface to embed error, like so:
package main
import (
"fmt"
)
type myerr interface {
error // <--- note: embedding 'error' here
Apple() string
}
type dummy struct {
age int
name string
}
func (d *dummy) Apple() string {
return fmt.Sprintf("%d --- %s", d.age, d.name)
}
// <--- note: implement the 'error' interface for the 'dummy' type
func (d *dummy) Error() string {
return fmt.Sprintf("%d ---- %s", d.age, d.name)
}
func f1(arg int) (string, myerr) {
return "f1", &dummy{arg, "ret"}
}
func main() {
i, j := f1(42)
fmt.Println(i)
fmt.Println(j)
}
This should invoke the Error method of j as you'd expect.
You can try it on the Go playground.
I'm in the process of learning go and am adapting a Java Game of Life example from testdouble. However, the test spy I have written incorrectly compares equality of my World struct - the test passes when it should fail, since output(world) is not being called. What am I doing incorrectly?
Test:
package gameoflife
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestZeroGenerations(t *testing.T) {
generatesSeedWorldStub := GeneratesSeedWorldStub{}
outputsWorldSpy := OutputsWorldSpy{}
conway := NewSimulatesConway(&generatesSeedWorldStub, &outputsWorldSpy)
seedWorld := World{}
conway.simulate()
correctWorld := outputsWorldSpy.wasOutputCalledWithWorld(seedWorld)
if !correctWorld {
t.Errorf("Output called with seed world, expected: %t, got: %t", true, correctWorld)
}
}
type GeneratesSeedWorldStub struct{}
func (gsw *GeneratesSeedWorldStub) generate() World {
return World{}
}
type OutputsWorldSpy struct {
outputCalledWithWorld World
}
func (ow *OutputsWorldSpy) output(world World) {
ow.outputCalledWithWorld = world
}
func (ow *OutputsWorldSpy) wasOutputCalledWithWorld(world World) bool {
return cmp.Equal(world, ow.outputCalledWithWorld)
}
Implementation:
package gameoflife
type SimulatesConway struct {
generatesSeedWorld GeneratesSeedWorld
outputsWorld OutputsWorld
}
func NewSimulatesConway(generatesSeedWorld GeneratesSeedWorld, outputsWorld OutputsWorld) SimulatesConway {
return SimulatesConway{generatesSeedWorld: generatesSeedWorld, outputsWorld: outputsWorld}
}
func (sc *SimulatesConway) simulate() {
// seedWorld := sc.generatesSeedWorld.generate()
// sc.outputsWorld.output(seedWorld)
}
type GeneratesSeedWorld interface {
generate() World
}
type OutputsWorld interface {
output(world World)
}
type World struct{}
When called outputsWorldSpy := OutputsWorldSpy{} golang assigned default value in outputsWorldSpy.outputCalledWithWorld = World{} and you assigned seedWorld := World{}. So they are same that's why test passed. If you want to handle that case, i suggest to use pointer.
type OutputsWorldSpy struct {
outputCalledWithWorld *World
}
func (ow *OutputsWorldSpy) output(world World) {
ow.outputCalledWithWorld = &world
}
func (ow *OutputsWorldSpy) wasOutputCalledWithWorld(world World) bool {
if ow.outputCalledWithWorld == nil {
return false
}
return cmp.Equal(world, *ow.outputCalledWithWorld)
}
I have an interface named Being, which requires two methods SetValue(v int) and GetValue() int. Then I have a base class Animal implementing it, and further a subclass Cat inherited from Animal.
Following is the code (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
func (a Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
func MakeCat() Being {
return Cat{}
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
However, the output is 0, rather than 1.
If I slightly modify the code to this (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
//Change the receiver to a pointer
func (a *Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
//Return the pointer
func MakeCat() Being {
cat := Cat{}
return &cat
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
where the modifications are marked by comments, the code behaves correctly, and output 1.
I cannot think of the reason of such phenomena, could anyone help?
I'm trying to add a pointer to a struct to a slice, but I can't get rid of this error:
cannot use NewDog() (type *Dog) as type *Animal in append:
*Animal is pointer to interface, not interface
How can I avoid this error? (while still using pointers)
package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]*Animal, 2)
pets[0] = NewDog()
(*pets[0]).Speak()
}
package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
You don't need a Slice of pointers to Animal interfaces.
http://golang.org/doc/effective_go.html#pointers_vs_values
just change your code to:
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
a interface value is already an implicit pointer.