Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito: mocking a method of same class called by method under test when using @InjectMocks

Tags:

java

mockito

I have a class I want to test that has several external dependencies, and a couple internal methods. I would like to write a test for MethodA, but not have Method A's internal call to MethodB to actually exercise MethodB. I'd like to mock/stub MethodB and return something specific instead. Usually I'd use when/thenReturn but it doesn't behave like I expect - it actually jumps into Method B while creating the mock itself.

MyService.java

@Service
public class MyService {

  @Autowired
  private ServiceA serviceA;

  @Autowired
  private ServiceB serviceB;

    public SomeObject methodA() {
      // some logic using serviceA.method and serviceB.method that creates "output"
      SomeObject someObject = methodB(output);
      return someObject;
    }

    public SomeObject methodB(SomeObject someObject) {
      // deep mysteries done here to someObject
      return someObject 
    }
}

MyServiceTest.java

public class MyServiceTest {

  @Mock
  private ServiceA serviceA;

  @Mock
  private ServiceB serviceB;

  @InjectMocks
  private MyService myService;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void methodATest() {
    when(serviceA.method()).thenReturn(stuff);
    when(serviceB.method()).thenReturn(otherStuff);

    // here is what I would like to do
    when(myService.methodB()).thenReturn(mockedSomeObject); //<- doesn't work

    assertThat(myService.methodA().getSomeObjectProperty())
        .isEqualTo("property");
  }
}

I've looked at solutions that manually mock the MyService class with Mockito.mock(MyService.class), but (as the above example is obviously contrived) my actual class has quite a few external dependencies and I'd prefer a solution that still allows me to mock the service using @Mock for the @Autowired dependencies and @InitMocks for the class under test, unless it's simply not possible.

I've tried:

Mockito.doReturn(mockedSomeObject).when(myService.methodB(any(SomeObject.class));

but that also steps into MethodB when creating the mock for that method, which shouldn't be happening.

Thanks in advance for the help!

like image 488
tengen Avatar asked Jun 04 '18 15:06

tengen


2 Answers

Try Adding @Spy to your InjectMocks and use the object to "expect" them in a slightly different syntax.

import org.mockito.Spy;

 @InjectMocks
 @Spy
 private MyService myService; 

And now mock the service call

 Mockito.doReturn(mockedSomeObject).when(myService).methodB();

Also change the other mock call to this

Mockito.doReturn(stuff).when(serviceA).method();
Mockito.doReturn(otherStuff).when(serviceB).method();
like image 121
lrathod Avatar answered Mar 05 '23 01:03

lrathod


You need to mark your object as Spy or explicitly create a Spy object for it using MyClass objA=null; MyClass spy_objA=Powermockito.spy(objA) doReturn(what_you_want).when(spy_objA).method()

Edit: Can find a similar question you may want to check How to mock another method in the same class which is being tested?

like image 37
varkashy Avatar answered Mar 05 '23 00:03

varkashy