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

*爱你&永不变心* 提交于 2020-01-11 06:46:43

问题


My user class is as follows,

public class UserResource {
  @Inject UserService userService;

  public boolean createUser(User user) {
    DbResponse res = userService.addUser(user);
    if(res.isSuccess){
      return true;
    }else{
      return false;
    }
  }
}

My test class looks as follows,

public class UserResourceTest {

  UserResource userResource;

  @BeforeMethod
  void beforeMethod() {
    userResource = new UserResource();
  }

  @Test
  public void test() {
    User user= mock(User.class);
    boolean res= userResource.createUser(user);
    assert(res);
  }
}

As you can see a UserService object should be injected into the UserResource class. How can I inject a mock UserService object to userResource object inside my test?

FYI:

  • This is part of a Jersey JAX-RS project.
  • I'm using Java CDI, mockito and testNG (as the test library).

回答1:


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);
  }
}



回答2:


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.



来源:https://stackoverflow.com/questions/48256831/how-to-inject-a-mock-object-to-a-class-when-testing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!