Mocking just one function in Go [duplicate] - unit-testing

This question already has answers here:
Is it possible to mock a function imported from a package?
(5 answers)
Closed last year.
I've read a bunch about this and don't understand why mocking is so complicated in Go. Is there a simple way to mock just one function?
For example:
func addB(num int) int {
return b() + num;
}
func getB() int {
return 3;
}
If I want to test addB but change getB to respond with 6 or something instead, in other languages I'd write a unit test like:
expect(getB).toBeCalled.andRespond(5);
assertEqual(addB(2), 7);
I don't see a way to do the mocking in Go without creating an object with getB as one of its methods, creating an interface for that object, and then including a test interface sent with addB. Is that really the best way to do it?

You can declare a function as a variable and inject a mock implementation for the tests.
Example:
package main
import "fmt"
var getB = func() int {
return 3
}
func main() {
fmt.Println(getB())
getB = func() int {
return 5
}
fmt.Println(getB())
}

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

Is DI(dependency injection) necessary for mocking dependencies in golang?

When I try to unit test a function as below, where extern_pkg is an external package to be mocked:
import "extern_pkg"
func MyFunc() {
...
extern_pkg.F()
}
func main() {
MyFunc()
}
I read a few blogs, and they all seem to achieve this by modifying prod code with dependency injection. For example, as below:
type exter interface {
F()
}
func MyFunc(e exter) {
...
e.F()
}
type extpkg struct{}
func (extpkg) F() {extern_pkg.F()}
func main() {
epkg := extpkg{}
MyFunc(epkg)
}
Then in test code, create a mock object that satisfies exter interface, and pass to MyFunc as parameter.
My question is:
If the MyFunc function contains many external packages to mock, do I need to DI each one as function parameters? Is it also true for any global variables the function depends on?
var global_var
func MyFunc() {
...
extern_pkg1.F()
...
extern_pkg2.G()
...
extern_pkg3.H()
...
global_var
}
Is there way to avoid modifying prod code?
Thanks!
Try use vars of func types and inject them. It is easier, lesser code and interfaces are not needed. See godif

assert_called_once() or assert_called_xyz().... equivalent?

It is important to me to be able to assert how many times a fake / mocked method is called in my tests and I'm wondering what is the best way to do this without using something like testify. In my case, the call to the mocked method is the result of some recursive call.
Lets say I have table driven tests with various animals, I want to assert that Hello is actually called for some tests but not for others. In some cases, it should be called more than once for given test (iterating over a slice).
Is it appropriate to just add a counter and make an assertion on that in my table driven test? It seems to me like maybe there is a better way to do this.
If I do add a counter to the hello method... where is it appropriate to deal with and check this. In the fake method itself or in the test etc?
type fakeFarmService struct {
abc.someFarmServiceInterface
}
func (f *fakeFarmService) Hello(ctx context.Context, in *abc.FarmRequest) (*abc.FarmResponse, error) {
if in.GetAnimal() == Monkey {
return &abc.HelloResponse{}, nil
}
return nil, errors.New("an error")
}
I've used the approach of counter on the struct and then asserting it inside the package level unit test multiple times in the past. Still, it's probably only until the level of package, when you would like to test such an internal assertions. I believe it's an accepted way of doing this in Go. Just be careful about properly synchronizing the access to the counter, if you decide to use a global variable or run the tests concurrently.
package main
import (
"fmt"
"sync"
"testing"
)
type fakeable interface {
Hello()
}
type fakeFarmService struct {
mu sync.Mutex
counter int
}
func (f *fakeFarmService) Hello() {
f.mu.Lock()
f.counter++
f.mu.Unlock()
}
func helloCaller(callee fakeable) {
callee.Hello()
}
func TestCallingTheHello(t *testing.T) {
fakeSvc := &fakeFarmService{}
helloCaller(fakeSvc)
helloCaller(fakeSvc)
// we expect that Hello method of fakeable was called 2 times
fakeSvc.mu.Lock()
defer fakeSvc.mu.Unlock()
if c := fakeSvc.counter; c != 2 {
t.Errorf("unexpected call count, want 2, got %d", c)
}
}
func main() {
TestCallingTheHello(&testing.T{})
}
https://play.golang.org/p/RXKuLKIZwc (test error won't work inside the playground)
Some good material on advanced testing in Go
Testing Techniques by Andrew Gerrand
NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto

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

Mocking a method using Mockito

Does mocking a method using mockito ensures that mocked method will never be called? I have Main class which contains some code i want to write unit tests for and i have one unit test class MainTest which contains unit tests for Main class.
eg:
Source Class:
package abc;
public class Main {
public int check1() {
int num = 10;
num = modify(num);
return num;
}
public int modify(int num) {
if (num % 10 == 0) return num / 10;
return -1;
}
}
Junit Test (using mockito)
package abc;
import junit.framework.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
public class MainTest {
private static Main main;
#BeforeClass
public static void setUp() {
main = Mockito.mock(Main.class);
Mockito.when(main.modify(10)).thenReturn(5);
}
#Test
public void testCheck1() {
Test1 main1 = new Main();
int num = main.check1();
Assert.assertEquals(5, num);
}
}
This test is failing. Why?
EDITED
Because you didn't provide a behavior for check1(). ALL methods get mocked, so without you providing a behavior, check1() returns a default value for the return type of int, which is 0. Furthermore, check1() since it is mocked does not even get to call modify().
If you are trying to test a class, you never mock the Class Under Test. On rare occasion, you might have to Spy a class under test. Rather, you mock collaborators only.
I am guessing your example was a contrived one (I hope). But if you are writing and testing a class where you think you want to modify some internal method's behavior, I see two likely probabilities:
You may need to refactor the functionality of the method you want to mock-out into a collaborator class. Then it makes sense to go ahead and mock that behavior as a collaborator.
You may also may need to modify the API so that you can pass in what is going to change. In your case, check1() hard-codes the value it passes to modify(), which is why you are trying to mock modify(). If instead that value were a parameter to check1() or a settable field in class Main, then there wouldn't even be a need to use a mock at all.
The Problem with your Test is, that you do not use your newly created main1 object.
If you want to change the behaviour of your systen under test (SUT) you would normally do something like this:
#Test
public void testCheck1() {
Test1 main1 = new Main(){
public int modify(int num) {
return 5; // hard coded return value
}
};
int num = main1.check1();
Assert.assertEquals(5, num);
}
This creates a subclass of Main with a new implementation of the modify-method.
This is an important technique for replacing hard-to-test methods in your SUT. You would normally use it to avoid expensive remote calls or similar.
It is of course possible to use a Mockito spy like this:
#Test
public void testCheck1() {
Test1 main1 = spy(new Main());
stub(main1.modify(10)).toReturn(5);
int num = main1.check1();
Assert.assertEquals(5, num);
}
Though i am late,it might be useful to some one. Just to add to #VivaceVivo answer: when using spies please consider doReturn|Answer|Throw() family of methods for stubbing. Sometimes it's impossible or impractical to use when(Object) for stubbing spies. more info here