14

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!

2 Answers 2

38

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();
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you - I had tried each of these changes on their own, but never together - this worked perfectly!
Happy that i was able to help you.
@lrathod , there is any difference between using when(serviceA.method()).ThenReturn(stuff) and doReturn(stuff).when(serviceA).method() ??
@Eric, When you are using the "Spy" , you will need to use the latter. Functionally both does the same though.
AFAIK you wouldn't need to replace the mock calls to the other mocked serviceA and serviceB. Then remain as mocks (not spies), so there is no difference between thenReturn and doReturn
1

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?

1 Comment

Thanks for the idea - however I'd prefer not to use PowerMockito unless there is really no way to accomplish this with "regular" Mockito.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.