How to inject a mock object to a class when testing?

前端 未结 2 1390
無奈伤痛
無奈伤痛 2021-01-14 19:11

My user class is as follows,

public class UserResource {
  @Inject UserService userService;

  public boolean createUser(User user) {
    DbResponse res          


        
相关标签:
2条回答
  • 2021-01-14 19:18

    Consider using explicit dependency principal via constructor injection as it states very clearly what is required by the class in order to perform its particular function.

    public class UserResource {
      private UserService userService;
    
      @Inject
      public UserResource(UserService userService) {
        this.userService = userService;
      }
    
      public boolean createUser(User user) {
        DbResponse res = userService.addUser(user);
        if(res.isSuccess){
          return true;
        }else{
          return false;
        }
      }
    }
    

    and mock the UserService as well and assign it to the subject under test. Configure the desired/mocked behavior for the test.

    public class UserResourceTest {
    
      @Test
      public void test() {
        //Arrange
        boolean expected = true; 
        DbResponse mockResponse = mock(DbResponse.class);
        when(mockResponse.isSuccess).thenReturn(expected);
    
        User user = mock(User.class);
        UserService mockService = mock(UserService.class);
        when(mockService.addUser(user)).thenReturn(mockResponse);
    
        UserResource userResource = new UserResource(mockService);        
    
        //Act
        boolean actual = userResource.createUser(user);
    
        //Assert
        assert(expected == actual);
      }
    }
    
    0 讨论(0)
  • 2021-01-14 19:18

    Although I completely support the answer of @Nkosi I'd like to add this for completeness:

    Use Mockitos JUnitRule to reate the mocks as described here: http://www.vogella.com/tutorials/Mockito/article.html :

    public class UserResourceTest {
        @Rule 
        public MockitoRule mockitoRule = MockitoJUnit.rule(); 
        @Mock
        private  DbResponse mockResponse;
        @Mock
        private UserService mockService;    
    
        @Test
        public void test() {
            //Arrange
            boolean expected = true; 
            when(mockResponse.isSuccess).thenReturn(expected);
            when(mockService.addUser(user)).thenReturn(mockResponse);
            // ...
    

    Also then you could also use Mockitos @InjectMocks annotation like this:

    public class UserResourceTest {
        @Rule 
        public MockitoRule mockitoRule = MockitoJUnit.rule(); 
        @Mock
        private  DbResponse mockResponse;
        @Mock
        private UserService mockService;
        @InjectMocks
        private UserResource userResource; // do not instantiate in test method
         // ...
    

    But I personally would discourage from it.

    Yes, it is more convenient since it determines by reflection which dependency injection method you use. But if you don't have a "seam" to inject a certain dependency (neither Costructor parameter, non final property nor setter of matching type) you don't get a compile error which I personally find problematic.

    0 讨论(0)
提交回复
热议问题