Shyna
Shyna

Reputation: 145

Unit testing with Mockitos not working as expected

I am new with Mockito and I wanted to write a unit test for some legacy code. I did try few techniques mentioned for using mockito while testing my specific scenario but I am not able to find a solution to my usecase. Here is my scenario :

I have a method A( does local processing of data) and a method B (does some remote processing of data). Method A in turn calls my method B. I want to call method A and when it in turn calls method B, then I want to return a predefined value from method B, lets says a list of files. Here is the sample code from Test class and actual class:

Myclass mc = Mockito.mock(MyClass.class);
when(mc.methodB(param1,param2)).thenReturn(fileSet); // returns mocked fileSet (set of files)
when(mc.methodA(param1,param2)).thenCallRealMethod();  //calls real method A
mc.methodA(param1,param2); //does not return the mocked value from methodB

class MyClass{
   public Set<File> methodB(param1,param2){
        //some processing
        return fileSet;
   }

   public void methodA(param1,param2){
        //some processing
        Set<FileSet> fileSet = methodB(param1,param2);
       //some more processing on returned files
   }

}

I created a mock of my class and made sure that when I invoke method A, real method call for method A happens and when I invoke method B, mock results are returned.

If I test method A and method B separately it works but when I call method A which in turn calls method B, it does not return my mocked value from method B.

Is this not the right way of doing this call or am I missing something?

Upvotes: 0

Views: 125

Answers (1)

Tunaki
Tunaki

Reputation: 137279

If I understand correctly, you want to mock one method from a class while really calling another method from the same class.

This can be done using spies: with spies, every method from the object is really called, unless it was explicitely stubbed:

MyClass myClass = new MyClass();
MyClass spy = spy(myClass); // creates a spy for myClass
doReturn(new HashSet<File>() {{ add(new File("file1")); }}).when(spy).methodB("", ""); // stubbing method B
spy.methodA(param1, param2); // calling the real method A

Note that spies should be used carefully, only to deal with legacy code that you cannot change.

Note that the construct to stub methodB differs from the "usual" construct. If we write the following code:

when(spy.methodB("", "")).thenReturn(...);

what is happening is that the real methodB is getting actually called right here, and this is something we do not want. In the second construct:

doReturn(...).when(spy).methodB("", "");

the methodB is not called.

Here's a complete test class demonstrating spies:

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import java.io.File;
import java.util.HashSet;
import java.util.Set;

import org.junit.Test;

public class TestClass {

    @Test
    public void test() {
        MyClass myClass = new MyClass();
        MyClass spy = spy(myClass); // creates a spy for myClass
        doReturn(new HashSet<File>() {{ add(new File("file1")); }}).when(spy).methodB("", ""); // stubbing method B
        spy.methodA("", ""); // calling the real method A
    }

}

class MyClass {

    public Set<File> methodB(String param1, String param2) {
        return new HashSet<File>() {{ add(new File("file2")); }};
    }

    public void methodA(String param1, String param2) {
        Set<File> fileSet = methodB(param1, param2);
        System.out.println(fileSet); // prints [file1] and not [file2], meaning the stubbed method was called and not the real one
    }

}

Upvotes: 1

Related Questions