How to test a struct that calls its own method? - unit-testing

I have a struct:
type foo struct {
bar mockableInterface // some interface that I can mock
}
func (f *foo) DoSmth1() []interface{} {
return f.bar.Bar()
}
func (f *foo) DoSmth2() []interface{} {
res := f.DoSmth1()
//some code to test
}
Here I have no problem with mocking bar and testing DoSmth1(). But it's not obvious how to test DoSmth2().
Should I rewrite this method to make it testable or rewrite tests somehow?

#mkopriva recommended just to mock Bar() call in DoSmth2() test. But in this case I would rewrite tests for all method that calls DoSmth1() every time it changes. So I've come to the following solution. We can encapsulate this mock logic in one method:
func (s *TestSuite) ExpectDoSmth1(times int, in, out []interface{}) {
s.barMock.Expect().Bar(in...).Times(times).Return(out...)
}
This way we can change only this method if DoSmth1() implementation changes, till its API stays the same

Related

How do we write unit test for a function using goroutine? considering inside function is being used with/without goroutine

so i have function without routine
func ContainsWithoutGoroutine() return {
someFunction()
return
}
and there is mock of someFunction
type DummyMock struct {
mock.mock
}
func(t *DummyMock) someFunction() {
//
}
to write the unit test for ContainsWithoutGoroutine we could easily mock someFunction and test it.
and now suppose i added a function with goroutine ContainsGoroutine
func ContainsGoroutine() return {
go func() {
someFunction()
}()
return
}
could not able to write unit test until we update the mock to something like this
type DummyMock struct {
mock.mock
Wg sync.WaitGroup
}
func(t *DummyMock) someFunction() {
defer t.Wg.Done()
//
}
and in the unit test of ContainsGoroutine need to add additional mock.Add(1) mock.Wg.Wait
after that unit test for ContainsGoroutine will work, but ContainsWithoutGoroutine will start failing
i know we could add same mock.Add(1) mock.Wg.Wait for the unit test of ContainsWithoutGoroutine to make it work , which i don't want to do that , As consider for the case where someFunction has been already being used in lot of places where there was no go routine and all that unit tests need to be changed.
is there a better way to structure this or maybe write unit test differently

Golang stretchr testify mock calls to a function within same class

I am pretty new to Golang and writing unit test for a function (I am using stretchr testify for mocks). This function however calls another function in same class. But when unit testing the first function, I want to mock the call to second function because I do not want it to call the second function in real. This was easy in Java, but I am not finding any useful information for this in Go. Here is some code snippet for my functions:
func (p *Prod) GetProducts(name string, request *prod.ProductRequest) (detail *prod.Department, err error) {
....
....
if err = p.getDetails(ctx, detail.Id); err != nil {
logger.Error(err)
return
}
...
...
}
func (p *Prod) GetDetails(name string, Id string) error {
....
....
}
As you can see here, GetProducts is the function that I am trying to unit test and this function calls GetDetails. I would like to mock the call to GetDetails. Is this possible in Go? Do we typically mock such function calls in Go. Is it recommended? If yes, whats the right way to do it?
In my test, I have:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &Prod{
...
ds: tt.fields.ds,
}
p.GetProducts("somestring", request)
})
}
This calls the function GetProducts. But now I don't know what changes to make so the call to GetDetails can be mocked. I would appreciate any help on this

How do I mock a function from another package without using dependency injection?

Somewhat of a golang beginner, but I've worked with testing frameworks before. How do I go about mocking out and faking what a dependent method returns without injecting the dependency? The reason why I don't want to use dependency injection is because there are many external package methods that are being used and injecting all of the methods in the constructor is unwieldy.
I've searched for this online/stackoverflow and the solution is to always use dependency injection. Sometimes that is not a viable option.
Here's what I'm trying to do code-wise:
b/b_test.go
package b
func TestResults(t *testing.T) {
t.Run("Test", func(t *testing.T) {
b := NewB()
// How do I mock out and fake a.DoSomething() to be
// "complete" instead of whats in the code right now?
result = b.Results()
assert.Equal(t, "complete", result)
}
}
b/b.go
package b
import "a"
type B struct {}
func NewB() B {
return &B{}
}
func (b B) Results() {
return a.DoSomething()
}
a/a.go
package a
func DoSomething() {
return "done"
}
Thanks!
You can use conditional compilation with build tags
a/a.go
// +build !mock
package a
func DoSomething() {
return "done"
}
a/a_mock.go
// +build mock
package a
func DoSomething() { // Insert fake implementation here
return "complete"
}
$ go test -tags mock
One way to do so would be to create a variable with the function you want to call, so include the following in b/b.go:
var doSomething = a.DoSomething
func (b B) Results() {
return doSomething()
}
Now in b_test.go you can do this:
func TestPrintResults(t *testing.T) {
origDoSomething := doSomething
defer func() { doSomething = origDoSomething }
doSomething = func() {
// Insert fake implementation here
}
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
I'm not sure if I don't understand your objection to dependency injection, but interfaces can be used to make dependency injection relatively painless. In particular existing code does not need to be modified.
You could try aliasing the package name to a global variable that implements an interface that matches the external package's functions. This has the advantage of not requiring inline changes where package "a" is used.
The idea revolves around creating an interface for the functions you need from the external package, a pass-through implementation of that interface for the default behavior and a mock implementation for testing. At the beginning of a test just replace the global variable with the mock.
b/a_interface.go
package b
import (
aa "a" // alias the "a" package
)
// global variable that mimics the external package "a"
var a aType
// internal interface for `a` package functions (i.e. `DoSomething()`)
type aDoer interface {
DoSomething() string
}
// default implementation of the aDoer interface
type aType struct{}
func (aType) DoSomething() string {
// just pass-through to package "a"
return aa.DoSomething()
}
b/b.go - is unmodified other then removing the import:
package b
type B struct{}
func NewB() B {
return B{}
}
func (b B) Results() string{
// now `a` is a global variable not a package.
return a.DoSomething()
}
b/b_test.go
package b
import (
"testing"
"github.com/stretchr/testify/assert"
)
// mock implementation of aDoer interface
type aMock struct{}
func (aMock) DoSomething() string {
return "complete"
}
func TestResults(t *testing.T) {
a = aMock{} // <- replace the default with the mock
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
It's a bit on the sneaky side, so you'll probably want to make clear comments about what's going on.

How to test call expectation in Go

I have a class MyClass that I want to test.
MyClass has a void method that calls an inner server to do something.
func (d *MyClass) SendToServer(args)
do stuff....
server.Send(myMessage)
I want to mock the server call Send, but since the method is a void method I can't be sure that I am actually calling it right.
These are the options I had in mind:
Use gomock, mock the server, and set expectations on the send method of the service
create my own MockServer, and "override" the method Send with a bunch of verifications. Something like:
func (d *MockedServer) Send(message)
// verify message...
create my own MockServer, but instead of verifying the expectation within the method, add the message to a list of messages, and then verify the content of the list.
What is a better approach in Go?
You could make a function out of your method like this:
var sendToServer = (*Server).Send
func func (d *MyClass) SendToServer(args) {
// ...
sendToServer(server, msg)
// ...
}
And in your tests:
func TestMyClass_SendToServer(t *testing.T) {
// ...
sent := false
sendToServer = func(*Server, args) {
sent = true
}
mc.SendToServer(args)
if !sent {
t.Error("fail")
}
}
This is described in Andrew Gerrand's Testing Techniques talk.

Golang: Replace function unit testing

I'm working with Golang, and currently I'm doing some fun unit test with Testify, my file look like this
type myStruct struct {
field_1 string
}
func (self *myStruct) writeFirst() {
//doing something
//modify field_1
self.writeSecond()
}
func (self *myStruct) writeSecond() {
//doing something
}
In this case I'm testing writeFirst() but I'm trying to replace writeSecond() because it is using http stuff that I don't want to use because it access to internet.
I think that use a second struct and set myStruct as anonymous field will be the solution, but it's not working because me second struct and myStruct have a diferent context.
In this case I can't use mocks cause writeSecond is a method of the struct.
My test case looks like this:
func TestWriteFirst(t *testing.T) {
myStc := myStruct{}
assert.Equal(t,"My response", myStc.field_1)
}
All that I want is testing writeFirst without pass to writeSecond()
To illustrate the kind of refactoring mentioned by Not-a-Golfer in the comments, you could consider calling your second function only on an instance that is an interface:
type F2er interface {
Func2()
}
type S struct{ _f2 F2er }
var s = &S{}
func (s *S) f2() F2er {
if s._f2 == nil {
return s
}
return s._f2
}
func (s *S) Func1() {
fmt.Println("s.Func1")
s.f2().Func2()
}
Here: Func1 calls Func2 on s.f2(), not directly s.
If nothing has been set in s, s.f2() returns... itself: s
if s._f2 was replaced by any other struct which implements Func2, s.f2() returns that instance instead of itself.
See a complete example in this playground script.
Output:
TestFunc1
s.Func1
s.Func2
TestFunc1bis
s.Func1
testS.Func2 <=== different Func2 call