我们什么时候应该使用@InjectMocks?

Fra*_*ung 4 testing junit mockito

我已经阅读了很多有关@Mock和@InjectMocks的讨论,但仍然找不到使用@InjectMocks的合适情况或必要情况。实际上,我不确定使用@InjectMocks时会发生什么。

考虑以下示例,

public class User {
  private String user_name;
  private int user_id;
  public User(int user_id) {
    this.user_id = user_id;
  }
  public String getUser_name() {
    return user_name;
  }
  public void setUser_name(String user_name) {
    this.user_name = user_name;
  }
  public int getUser_id() {
    return user_id;
  }
  public void setUser_id(int user_id) {
    this.user_id = user_id;
  }     
}

public interface UserDao {
  public List<User> getUserList();
}

public class UserService {
  private UserDao userDao;  
  public UserDao getUserDao() {
    return userDao;
  }
  public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  }
  public List<User> getUserList() {
    return userDao.getUserList();
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的考试课

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {  
  private UserService service = new UserService();
  @Mock
  private UserDao dao;

  @Test
  public void testGetUserList() {

    service.setUserDao(dao);

    // mock the return value of the mock object
    List<User> mockResult = Arrays.asList(new User(101),new User(102),new User(103));       
    when(dao.getUserList()).thenReturn(mockResult);

    // check return value is same as mocked value
    assertEquals(service.getUserList(),mockResult);

    // verify the getUserList() function is called
    verify(dao).getUserList();  
  }
}    
Run Code Online (Sandbox Code Playgroud)

测试成功运行,没有错误。考虑使用@InjectMock批注的另一种方法。

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {  

  @InjectMocks
  private UserService service;
  @Mock
  private UserDao dao;

  @Test
  public void testGetUserList() {

    service.setUserDao(dao);

    // mock the return value of the mock object
    List<User> mockResult = Arrays.asList(new User(101),new User(102),new User(103));       
    when(dao.getUserList()).thenReturn(mockResult);

    // check return value is same as mocked value
    assertEquals(service.getUserList(),mockResult);

    // verify the getUserList() function is called
    verify(dao).getUserList();  
  }
}    
Run Code Online (Sandbox Code Playgroud)

这同样有效。那么,哪种方法更好?有最佳做法吗?顺便说一句,我正在使用Junit 4.8.1和Mockito 1.9.5

Gho*_*ica 5

如果您没有提供进一步的代码,那么您的实际问题就无法回答(显示的代码不会解释您声称要遵守的结果)。

关于基本问题:您可能不应该使用@InjectMocks;其核心问题之一是:如果注射失败,不会的Mockito 报告错误给你。

换句话说:您已经通过了单元测试,并且有关字段的一些内部细节发生了变化……并且单元测试中断了;但是您不知道为什么……因为模拟框架没有告诉您将模拟放入被测类的“初始”步骤突然失败了。请参阅此处以进一步阅读。

但是要在这里明确:最后,这几乎是一个纯风格的问题。习惯@InjectMocks的人们会喜欢它。其他人反对。含义:没有明确的证据表明您是否应该使用此概念。取而代之的是:您研究了概念,理解了概念,然后您(以及与您一起工作的团队)做出了是否使用此批注的有意识的决定。

编辑:我想我现在解决你的问题。@InjectMocks的想法是注入一个嘲笑对象一些测试对象

但是:在两种情况下,您都是手动进行的:

 service.setUserDao(dao);
Run Code Online (Sandbox Code Playgroud)

含义:如果注入正常工作(并没有未被报道的Mockito的一个问题),那么你的榜样,它使用注释应该工作,当你删除一行。没有@InjectMocks的测试用例应该在没有该行的情况下失败

换句话说:您的测试用例都通过了,因为您的代码执行了“手动注入”!