How can I mock methods of @InjectMocks class?

前端 未结 3 1352
慢半拍i
慢半拍i 2021-01-30 03:02

For example I have handler:

@Component
public class MyHandler {

  @AutoWired
  private MyDependency myDependency;

  public int someMethod() {
    ...
    retur         


        
相关标签:
3条回答
  • 2021-01-30 03:30

    First of all the reason for mocking MyHandler methods can be the following: we already test anotherMethod() and it has complex logic, so why do we need to test it again (like a part of someMethod()) if we can just verify that it's calling?
    We can do it through:

    @RunWith(MockitoJUnitRunner.class}
    class MyHandlerTest {
    
      @Spy  
      @InjectMocks  
      private MyHandler myHandler;  
    
      @Mock  
      private MyDependency myDependency;  
    
      @Test  
      public void testSomeMethod() {  
        doReturn(1).when(myHandler).anotherMethod();  
        assertEquals(myHandler.someMethod() == 1);  
        verify(myHandler, times(1)).anotherMethod();  
      }  
    }  
    

    Note: in case of 'spying' object we need to use doReturn instead of thenReturn(little explanation is here)

    0 讨论(0)
  • 2021-01-30 03:44

    In your code, you are not testing MyHandler at all. You don't want to mock what you are testing, you want to call its actual methods. If MyHandler has dependencies, you mock them.

    Something like this:

    public interface MyDependency {
      public int otherMethod();
    }
    
    public class MyHandler {
      @AutoWired
      private MyDependency myDependency;
    
      public void someMethod() {
        myDependency.otherMethod();
      }
    }
    

    And in test:

    private MyDependency mockDependency;
    private MyHandler realHandler;
    
    @Before
    public void setup() {
       mockDependency = Mockito.mock(MyDependency.class);
       realHandler = new MyHandler();
       realhandler.setDependency(mockDependency); //but you might Springify this 
    }
    
    @Test
    public void testSomeMethod() {
    
      //specify behaviour of mock
      when(mockDependency.otherMethod()).thenReturn(1);
    
      //really call the method under test
      realHandler.someMethod();
    }
    

    The point is to really call the method under test, but mock any dependencies they may have (e.g. calling method of other classes)

    If those other classes are part of your application, then they'd have their own unit tests.

    NOTE the above code could be shortened with more annotations, but I wanted to make it more explicit for the sake of explanation (and also I can't remember what the annotations are :) )

    0 讨论(0)
  • 2021-01-30 03:47

    All answers above are really good and may be useful so make sure you study and understand these principes first before continue reading my post.

    In my scenario none of advices above did not work. I will post what helped me after a pretty long debugging.

    If you want to call methods from tested class, the @Spy annotation is needed alongside @InjectMocks (or Mockito.spy(XXX) call or course)

    The interesting part is, the order of these annotations does matter! The @Spy annotation must precede @InjectMocks annotation.

    Will not work

    ...
    
    @InjectMocks
    @Spy
    private TestedObject instance
    
    ...
    

    Will work

    ...
    
    @Spy
    @InjectMocks
    private TestedObject instance
    
    ...
    
    0 讨论(0)
提交回复
热议问题